iOS GCD自定义并发队列执行顺序

根据苹果的文件,我对这个问题有疑问

并发并发队列(也称为全局调度队列)同时执行一个或多个任务, 但是任务仍然按照它们被添加到队列的顺序启动。 当前正在执行的任务在由调度队列pipe理的不同线程上运行。 在任何给定点执行的任务的确切数量是可变的,并取决于系统条件。 在iOS 5及更高版本中,您可以通过将DISPATCH_QUEUE_CONCURRENT指定为队列types来自己创build并发调度队列。 此外,还有四个预定义的全局并发队列供您的应用程序使用。 有关如何获取全局并发队列的更多信息,请参阅获取全局并发调度队列。

我做了一个testing,使用示例代码,

dispatch_queue_t concurrentQueue; concurrentQueue = dispatch_queue_create("com.gcd.concurrentQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(concurrentQueue, ^{ NSLog(@"First job "); }); dispatch_async(concurrentQueue, ^{ NSLog(@"Second job"); }); dispatch_async(concurrentQueue, ^{ NSLog(@"Third job "); }); 

但是结果似乎并不像它们被添加的顺序,这里是结果,

 2015-06-03 18:36:38.114 GooglyPuff[58461:1110680] First job 2015-06-03 18:36:38.114 GooglyPuff[58461:1110682] Third job 2015-06-03 18:36:38.114 GooglyPuff[58461:1110679] Second job 

所以我的问题是,不应该是第一,第二,第三?

欢迎任何build议,并感谢您的帮助。

“同时”意味着他们在同一时间运行,并且不应该假定在他们的进展中,他们中的任何一个在任何时刻将会完成并且将首先完成。 这就是并发的全部意义和含义:在一行代码和下一行之间,即使一行代码中,任何其他并发操作都可能发生。

因此,针对您的特定问题,这些任务可能已经按照已知的顺序开始 ,但是发生得非常快,在那之后,它们的进展是不可预测地交错的。 你的NSLog调用是这个进程的一部分; 他们没有,也不能告诉你任务何时开始!

文档是正确的 – 它们的确会以您将它们添加到队列中的顺序启动。 一旦进入队列,它们将一个接一个地启动,但是在并发线程上。 他们将完成的顺序取决于任务执行的时间。 这是一个思想实验,想象你的代码是这样的:

  dispatch_async(concurrentQueue, ^{ JobThatTakes_3_SecToExecute(); // Job 1 (3 seconds to execute) }); dispatch_async(concurrentQueue, ^{ JobThatTakes_2_SecToExecute(); // Job 2 (2 seconds to execute) }); dispatch_async(concurrentQueue, ^{ JobThatTakes_1_SecToExecute(); // Job 3 (1 second to execute) }); 

与这些工作长度相比,进出队列的开销应该是非常小的,所以你期望他们在大约任务执行的时间内完成。 在这种情况下,他们完成大约1秒,从工作3开始,然后是2,然后是1.完成队列所需的总时间约为工作1的长度,因为执行时间最长。 这是可爱的,因为总时间主要由最长的工作决定,而不是工作总和。 然而,你不知道按照什么顺序完成,因为这是由任务持续时间决定的。

在此示例中将dispatch_async更改为dispatch_sync,队列大约需要6秒才能完成。 他们会按照这个顺序出来:Job 1,2,然后是3.这样可以保证你的结果按你想要的顺序出来,但是会花费更长的时间。

所以回到文档对于并发队列中的“任务仍然以添加到队列中的顺序开始”的含义的意义。 如果您的工作受到资源限制,这将是显而易见的。 假设您将一大堆长时间任务放在2台CPU机器的并发队列中。 你不太可能在这里同时运行12个CPU挂钩任务。 有些则需要等待别人跑步。 您将它们放入队列中的顺序将决定在资源释放时谁将接下来运行。 在你的例子中,任务是超短的,并涉及控制台locking(Rob提到),所以排队/locking开销可能会混淆你的期望。

另一个(可能更重要的)原因是并发队列中的执行顺序很重要,因为使用了障碍。 您可能需要每N个其他任务运行某种任务,这是障碍派上用场的地方。 执行的固定顺序将确保屏障在N个任务同时完成之后执行,只要您将屏障放在正确位置的队列中即可。