在getter中对背景线程进行大量计算

时间:2016-01-25 20:35:33

标签: ios multithreading grand-central-dispatch

每次从我的应用程序调用getter时,我都需要执行大量计算。从getter返回的数据会根据环境不断变化,并且必须进行大量计算才能计算应该返回的内容。因此,我不希望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,但我似乎没有正确实现它。

3 个答案:

答案 0 :(得分:2)

我认为使用回调可能是解决此问题的最简单,最有效的方法。

只是不可能只使用一个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.
}];

通过这种方式,您可以轻松地将生成的代码与对方法的调用保持一致。

还值得注意的是,你calculationQueue的吸气者(我将其重命名为,因为当你正在使用队列时,线程这个词会产生误导)并非如此线程安全的。我建议你使用dispatch_once使其成为线程安全的:

-(dispatch_queue_t) calculationQueue {

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _calculationQueue = dispatch_queue_create("calculation_queue", DISPATCH_QUEUE_SERIAL);
    });

    return _calculationQueue;
}

答案 1 :(得分:1)

您可以使用以下内容将其异步放入队列中。然而问题是该方法将立即返回。

dispatch_async(your_queue, ^{
    // Code to be executed on background thread
});

你可能想要的是拥有某种方法calculateWithCompletion,其中调用者可以定义一个完成完成后可以调用的块。

答案 2 :(得分:0)

正如你在对彼得的评论中所说,你想保留它,这样你就可以调用self.calculation并执行你的逻辑并同步返回计算。

但是,因为您希望在执行此逻辑时避免锁定UI,所以您希望它在后台线程上执行。

因此,您需要做的只是在dispatch_sync方法中使用dispatch_async而不是calculate

dispatch_sync的作用是将任务(包含您的逻辑的块)放到指定的队列(可能应该选择global concurrent queue),然后在操作系统选择的线程上执行您的任务为你(不是主线程)。 dispatch_async执行相同操作, dispatch_async将您的任务分派到队列后立即继续执行。

另一方面,

dispatch_sync将阻止当前运行循环中的执行,直到您的任务返回。

这将允许您在后台线程上执行昂贵的逻辑,同时仍然保持同步,以便您可以继续使用self.calculation