5

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

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

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

4

3 回答 3

17

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);
    });
});
于 2013-08-05T01:27:37.277 回答
7

同步 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")

产生无序的输出,如:

0  8  1  9  2  3  4  5  6  7  
dispatch_apply QOS_CLASS_UTILITY queue completed

因此,dispatch_apply调用时同步阻塞,但生成的“批处理”任务dispatch_apply可以并发、异步、并行运行。

请记住以下警告...

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

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

尽管使用串行队列是允许的,并且可以为您的代码做正确的事情,但使用这样的队列与保留循环相比并没有真正的性能优势。

于 2015-10-25T23:29:46.530 回答
0

您可以使用gcl_create_dispatch_queue()with来提高性能dispatch_apply()

例如:

@import Foundation;
@import OpenCL;        // gcl_create_dispatch_queue()

int main() {
      dispatch_queue_t queue = gcl_create_dispatch_queue(CL_DEVICE_TYPE_ALL, NULL);
      dispatch_apply(10, queue, ^(size_t t) {
           // some code here
      });
}

更多信息: Mac 的 OpenCL 编程指南

于 2017-08-05T12:37:14.337 回答