dispatch_apply是同步还是异步?

Jes*_*ica 5 concurrency objective-c

有人告诉我,我可以使用Grand Central Dispatch以异步方式同时运行n个进程.文档说如果进程在for循环中,我可以使用函数dispatch_apply.但现在它说

请注意,dispatch_apply是同步的,因此所有应用的块将在返回时完成.

这是否意味着使用dispatch_apply提交到队列的块按顺序执行?如果是这样,使用并发有什么意义?减速不会一样吗?

Seb*_*ian 14

dispatch_apply正如文档中所述,是同步的.它并行地在指定队列上运行一个块(如果可能的话),并等待所有块返回.如果要仅异步运行一次块,请使用dispatch_async,如果要并行多次运行块而不阻塞当前队列,只需dispatch_apply在dispatch_async以下内容中调用:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(size_t size) {
        NSLog(@"%lu", size);
    });
});
Run Code Online (Sandbox Code Playgroud)


l -*_*c l 6

同步 dispatch_apply的目的是异步地将内循环交互分配给可用的并行处理资源. 因此,整体循环性能可能加快.

更快的循环性能?很可能,是的.(见警告)

阻止线程调用dispatch_apply?是的,就像循环块一样,直到完成.

对于GCD,dispatch_apply是同步的,因为dispatch_apply不会返回,直到所有的异步,并行任务,即dispatch_apply创建完成.

但是,如果目标是异步的,那么排队的每个单独任务dispatch_apply都可以作为并发异步任务运行.queue

例如在Swift中:

let batchCount: Int = 10 
let queue = dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)
dispatch_apply(batchCount, queue) { 
   (i: Int) -> Void in
   print(i,  terminator: "  ")
}
print("\ndispatch_apply QOS_CLASS_UTILITY queue completed")
Run Code Online (Sandbox Code Playgroud)

产生无序输出,如:

0  8  1  9  2  3  4  5  6  7  
dispatch_apply QOS_CLASS_UTILITY queue completed
Run Code Online (Sandbox Code Playgroud)

因此,dispatch_apply在调用时同步阻塞,但生成的"批处理"任务dispatch_apply可以并行,异步,并行运行.

请记住......

在每次迭代期间执行的工作与在所有其他迭代期间执行的工作不同,并且每个连续循环完成的顺序并不重要

另请注意,为内循环任务使用串行队列不会有任何性能提升.

虽然允许使用串行队列并为您的代码做正确的事情,但使用这样的队列与将循环留在原位相比没有真正的性能优势.