如何使用 `NSOperationQueue` 阻塞 `dispatch_sync`

how to do blocking `dispatch_sync` using `NSOperationQueue`

有时我需要同步return。在 dispatch_sync 中只是:

__block int foo
dispatch_sync({
  foo = 3
});
return foo;

我不确定这如何转化为 NSOperationQueue。我检查了 maxConcurrentOperationCount = 1,但我不认为这是阻塞。我的理解是,这只会使操作队列“串行”,而不是“同步”。

可以在 Swift 中使用 addoperations:waitUntilFinished: (addOperations(_:waitUntilFinished:)),为第二个参数传递 true


为了未来的读者,虽然可以等待使用 waitUntilFinished,但 10 次中有 9 次是错误的。如果你有一些异步操作,它通常是有充分理由的异步,你应该拥抱异步模式并在你自己的代码中使用异步块完成处理程序参数,而不是强制它同步完成。

例如,而不是:

- (int)bar {
    __block int foo;

    NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        foo = 3;
    }];

    [self.queue addOperations:@[operation] waitUntilFinished:true];

    return foo;
}

一个人通常会这样做:

- (void)barWithCompletion:(void (^ _Nonnull)(int))completion {
    [self.queue addOperationWithBlock:^{
        completion(3);
    }];
}

[self barWithCompletion:^(int value) {
    // use `value` here
}];

// but not here, as the above runs asynchronously

当开发人员第一次遇到异步模式时,他们几乎总是试图与之抗争,使它们表现得同步,但这几乎总是一个错误。拥抱异步模式,不要对抗它们。

FWIW,Swift 中的新异步等待模式允许我们编写比传统异步 blocks/closures 更容易推理的异步代码。因此,如果 Swift 及其新的并发模式是一个选项,您也可以考虑。


在下面的评论中,您似乎关心操作队列与调度队列的同步行为的性能特征。出于性能原因,不会在调度队列上使用操作队列,而是如果您受益于添加的功能(包括依赖项、优先级、控制并发度、优雅的取消功能、在操作中包装异步进程等)。

如果性能是最佳考虑因素(例如,对于线程安全同步),os_unfair_lock 之类的东西会使调度队列性能黯然失色。但我们通常不会让性能决定我们的选择,除了 3% 的绝对需要的情况。我们尝试使用适合手头任务的最高级别的抽象(即使以适度的性能损失为代价)。