GCD 全局并发队列并不总是并发(iOS 设备)?
Posted
技术标签:
【中文标题】GCD 全局并发队列并不总是并发(iOS 设备)?【英文标题】:GCD global concurrent queue not always concurrent(iOS device)? 【发布时间】:2011-11-23 08:58:56 【问题描述】:在 ios 设备上,我最近发现了一个奇怪的行为。
代码1:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
NSLog(@"1111");
);
while (1)
sleep(1);
);
代码2:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
NSLog(@"1111");
);
while (1)
sleep(0.5);
);
Code1 和 Code2 的唯一区别是 Code1 每循环睡眠 1 秒,Code2 睡眠 0.5。
如果你在单核iOS设备上运行这两个代码,Code1会打印出@"1111",但Code2不会。
我不知道为什么,假设全局队列是并发的。无论其他块在做什么,它都应该始终打印出数字。如果是因为单核设备的限制,为什么 sleep(0.5) 和 sleep(1) 会有所不同?
我真的很想知道这是什么原因。
编辑
我发现使用 sleep(0.5) 是我的愚蠢错误。 sleep()
函数采用无符号整数参数。所以 sleep(0.5) 等于 sleep(0)。但是 sleep(0) 会阻塞整个并发队列吗?
【问题讨论】:
【参考方案1】:原因是你的第二个 sleep() 本质上是一个 sleep(0) 这意味着你现在正在循环 GCD 给你的线程,这可能是执行嵌套 dispatch_async 的同一个线程() 如果你给它一个机会做其他事情,第一个例子就是这样做的。在一秒钟的睡眠期间,GCD 看到线程被阻塞并创建一个新线程来服务未完成的排队请求。在第二个示例中,您基本上在计算上使排队的工作饿死 - GCD 不够聪明,无法知道线程已被锁定在无限循环中,并且您没有给系统足够的工作来证明(在 GCD 眼中)另一个线程的创建,所以...你基本上发现了 GCD 工作逻辑的低阈值中的一个错误,我认为。
【讨论】:
你的答案是正确的,但这不是一个错误,它只是 GCD 通过让单核 CPU 完成当前任务,然后再给它另一个同等优先级来提高效率。将繁忙线程的数量与可用内核的数量相匹配是 GCD 设计的基本部分。 这很奇怪。我决定测试一下,当您将新块分派到高优先级队列时,GCD 是否会挂起一个低优先级块。实际发生的情况是,它不仅不会暂停低优先级块,它实际上还会启动新的低优先级块,即使两个高优先级块仍在运行(这是在双核 A5 上)。它将奇怪地决定同时运行多达六个块,似乎不考虑它们被调度的全局队列的优先级。这似乎表明 iOS GCD 存在严重错误。【参考方案2】:刚刚签出,第一个和第二个 sn-ps 打印“1111”。
请注意,您使用的 dispatch_async 嵌套不会带来任何好处,因为您为所有任务“NSLog(@"1111");
”设置了相同的优先级(DISPATCH_QUEUE_PRIORITY_DEFAULT)
和“
while (1)
sleep(0.5);
"
将被添加到同一个目标队列中。结果,我可以假设在第一种情况下,带有 WHILE 的块将首先执行,并且因为它永远不会完成,所以永远不会调用队列中的下一个任务(NSLog(...))。
您可以尝试为队列使用不同的优先级 (DISPATCH_QUEUE_PRIORITY_LOW f.e.)。
【讨论】:
dispatch_get_global_queue() 函数返回的是全局队列(并发队列)。所以分派几个块到同一个并发队列应该没问题。while循环块不应该阻止nslog块执行 如果使用相同的优先级,则全局队列将相同 我知道队列是一样的。但是全局队列是并发的。调度到并发 GCD 队列的块应该是并发执行的,或者至少不会互相干扰。以上是关于GCD 全局并发队列并不总是并发(iOS 设备)?的主要内容,如果未能解决你的问题,请参考以下文章