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;
}