iOS GCD并发队列出现异常行为的原因是什么?
嘿,看你在研究GCD并发队列时遇到了异常,先把你的测试代码整理得更清晰些:
_syncQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); // 同步任务循环 for (int index = 0; index < 3; ++index) { dispatch_sync(_syncQueue, ^{ NSLog(@"sync@@@@@@ >>>> %d ",index); sleep(1); NSLog(@"sync@@@@@@ <<<< %d ",index); }); } // 异步任务循环 for (int index = 3; index < 6; ++index) { dispatch_async(_syncQueue, ^{ NSLog(@"sync===== >>>> %d ",index); sleep(1); NSLog(@"sync===== <<<< %d ",index); }); }
你大概率遇到的异常&背后原因
我猜你困惑的点要么是三个同步任务完全串行,没有并发执行,要么是异步任务非要等所有同步任务做完才开始跑——这俩其实都是dispatch_sync的特性导致的,不是队列的问题:
同步任务串行的本质
虽然_syncQueue是全局并发队列(理论上能同时跑多个任务),但dispatch_sync是「同步提交」:你调用它的当前线程会直接阻塞,直到提交的这个任务完完整整执行完毕,才会继续走循环里的下一次dispatch_sync。所以三个同步任务只能一个接一个来,每个任务睡1秒,总耗时刚好3秒左右。异步任务延迟启动的原因
前面的同步任务把当前线程卡得死死的,它根本没时间去提交后面的异步任务——只有等三个同步任务全部执行完,循环结束,才会轮到异步任务的循环开始提交任务。不过异步任务提交后,并发队列的特性就体现出来了:三个任务会在不同的线程上同时跑,你会看到它们的>>>>日志几乎同时打印,1秒后<<<<日志也会批量出现。
怎么验证并发队列的真实能力?
如果你想看到并发队列真的“并发”,把同步提交改成异步提交就行:
for (int index = 0; index < 3; ++index) { dispatch_async(_syncQueue, ^{ NSLog(@"sync@@@@@@ >>>> %d ",index); sleep(1); NSLog(@"sync@@@@@@ <<<< %d ",index); }); }
这时候三个任务会同时启动,你会瞬间看到三条>>>>日志,1秒后三条<<<<日志也会一起出来,这才是并发队列该有的样子。
另外提个小建议:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)是老API了,iOS 8之后推荐用基于QoS的新写法dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0),适配性更好。
内容的提问来源于stack exchange,提问作者onTheWay

