getter 中后台线程的繁重计算
Heavy calculations on a background thread in getter
每次从我的应用程序调用 getter 时,我都需要执行大量计算。来自 getter 的数据 return 会根据环境不断变化,它必须进行大量计算才能计算出它应该 return 的内容。因此,我不希望主线程上的 getter 运行 中的代码。这是我目前所拥有的:
@interface Calculator ()
@property (nonatomic, strong) dispatch_queue_t calculationThread;
@end
- (dispatch_queue_t)calculationThread {
if (!_calculationThread) {
_calculationThread = dispatch_queue_create("calculation_thread", NULL);
}
return _calculationThread;
}
- (NSArray *)calculation {
// perform calculation in calculationThread, which should not be on main thread and be asynchronous
return arrayContainingCalculations;
}
我主要是想知道怎么用GCD替换注释。我尝试过使用 dispatch_queue_t 和 dispatch_group_notify,但我似乎没有正确实施它。
您可以使用以下方法将其异步放入您的队列中。然而,问题是该方法将立即 return。
dispatch_async(your_queue, ^{
// Code to be executed on background thread
});
您可能需要某种方法 calculateWithCompletion
调用者可以在其中定义一个块,您可以在完成完成后调用该块。
正如您在对 Peter 的评论中所说,您想保留它以便调用 self.calculation
并同步执行逻辑和 return 计算。
但是,因为您想避免在执行此逻辑时锁定 UI,所以您希望它在后台线程上执行。
因此,您需要做的就是在 calculate
方法中使用 dispatch_sync
而不是 dispatch_async
。
dispatch_sync
所做的是将一个任务(包含您的逻辑的块)放入指定的队列(可能应该选择一个 global concurrent queue),然后在线程上执行您的任务OS 为您挑选(不是主线程)。 dispatch_async
做同样的事情,除了 dispatch_async
将在将任务分派到队列后立即继续执行。
另一方面,dispatch_sync
将阻止当前 运行 循环中的执行,直到您的任务 returns.
这将允许您在后台线程上执行昂贵的逻辑,同时仍保持同步,以便您可以继续使用 self.calculation
我认为使用回调可能是解决这个问题最简单有效的方法。
仅不可能仅使用一个getter进行异步计算而不阻塞调用它的线程,正如您期望在它之后调用的代码在计算时继续执行。
您只需创建一个带有回调的新方法,例如:
-(void) doCalculation:(void(^)(NSArray* result))callback {
dispatch_async(self.calculationQueue, ^{
NSArray* result = self.calculation; // make sure this is doing a synchronous calculation. If it's asynchronous, you'll have to use a semaphore (or another callback!).
if (callback) {
dispatch_async(dispatch_get_main_queue(), ^{ // return to main thread
callback(result);
});
}
});
}
然后您可以像这样在主线程上简单地调用它:
[calculator doCalculation:^(NSArray* result) {
textView.text = [result[0] stringValue]; // update UI with new info.
}];
这样您就可以通过调用该方法轻松保留生成的代码 in-line。
还值得注意的是,您的 calculationQueue
的 getter(我重命名了它,因为线程这个词在您使用队列时会产生误导)不是 thread-safe .我建议您使用 dispatch_once
使其成为 thread-safe:
-(dispatch_queue_t) calculationQueue {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_calculationQueue = dispatch_queue_create("calculation_queue", DISPATCH_QUEUE_SERIAL);
});
return _calculationQueue;
}
每次从我的应用程序调用 getter 时,我都需要执行大量计算。来自 getter 的数据 return 会根据环境不断变化,它必须进行大量计算才能计算出它应该 return 的内容。因此,我不希望主线程上的 getter 运行 中的代码。这是我目前所拥有的:
@interface Calculator ()
@property (nonatomic, strong) dispatch_queue_t calculationThread;
@end
- (dispatch_queue_t)calculationThread {
if (!_calculationThread) {
_calculationThread = dispatch_queue_create("calculation_thread", NULL);
}
return _calculationThread;
}
- (NSArray *)calculation {
// perform calculation in calculationThread, which should not be on main thread and be asynchronous
return arrayContainingCalculations;
}
我主要是想知道怎么用GCD替换注释。我尝试过使用 dispatch_queue_t 和 dispatch_group_notify,但我似乎没有正确实施它。
您可以使用以下方法将其异步放入您的队列中。然而,问题是该方法将立即 return。
dispatch_async(your_queue, ^{
// Code to be executed on background thread
});
您可能需要某种方法 calculateWithCompletion
调用者可以在其中定义一个块,您可以在完成完成后调用该块。
正如您在对 Peter 的评论中所说,您想保留它以便调用 self.calculation
并同步执行逻辑和 return 计算。
但是,因为您想避免在执行此逻辑时锁定 UI,所以您希望它在后台线程上执行。
因此,您需要做的就是在 calculate
方法中使用 dispatch_sync
而不是 dispatch_async
。
dispatch_sync
所做的是将一个任务(包含您的逻辑的块)放入指定的队列(可能应该选择一个 global concurrent queue),然后在线程上执行您的任务OS 为您挑选(不是主线程)。 dispatch_async
做同样的事情,除了 dispatch_async
将在将任务分派到队列后立即继续执行。
dispatch_sync
将阻止当前 运行 循环中的执行,直到您的任务 returns.
这将允许您在后台线程上执行昂贵的逻辑,同时仍保持同步,以便您可以继续使用 self.calculation
我认为使用回调可能是解决这个问题最简单有效的方法。
仅不可能仅使用一个getter进行异步计算而不阻塞调用它的线程,正如您期望在它之后调用的代码在计算时继续执行。
您只需创建一个带有回调的新方法,例如:
-(void) doCalculation:(void(^)(NSArray* result))callback {
dispatch_async(self.calculationQueue, ^{
NSArray* result = self.calculation; // make sure this is doing a synchronous calculation. If it's asynchronous, you'll have to use a semaphore (or another callback!).
if (callback) {
dispatch_async(dispatch_get_main_queue(), ^{ // return to main thread
callback(result);
});
}
});
}
然后您可以像这样在主线程上简单地调用它:
[calculator doCalculation:^(NSArray* result) {
textView.text = [result[0] stringValue]; // update UI with new info.
}];
这样您就可以通过调用该方法轻松保留生成的代码 in-line。
还值得注意的是,您的 calculationQueue
的 getter(我重命名了它,因为线程这个词在您使用队列时会产生误导)不是 thread-safe .我建议您使用 dispatch_once
使其成为 thread-safe:
-(dispatch_queue_t) calculationQueue {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_calculationQueue = dispatch_queue_create("calculation_queue", DISPATCH_QUEUE_SERIAL);
});
return _calculationQueue;
}