关于并发:GCD 全局并发队列不总是并发(iOS 设备)?

GCD global concurrent queue not always concurrent(iOS device)?

在 iOS 设备上,我最近发现了一个奇怪的行为。

代码1:

1
2
3
4
5
6
7
8
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:

1
2
3
4
5
6
7
8
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) 会阻塞整个并发队列吗?


原因是你的第二个 sleep() 本质上是一个 sleep(0),这意味着你现在正在循环 GCD 给你的线程,这可能是同一个线程如果您给了它一个机会做任何其他事情,则执行嵌套的 dispatch_async(),这是第一个示例所做的。在一秒钟的睡眠期间,GCD 看到线程被阻塞并创建一个新线程来服务未完成的排队请求。在第二个示例中,您实际上是在计算上使排队的工作饿死 - GCD 不够聪明,无法知道线程已被锁定在无限循环中,并且您没有给系统足够的工作来证明(在 GCD \\ 的眼睛)创建另一个线程,所以......我认为你基本上发现了 GCD 的低阈值工作逻辑中的一个错误。


刚刚签出,第 1 和第 2 个片段打印"1111"。
请注意,您使用的 dispatch_async 嵌套不会带来任何好处,因为您为所有任务 "NSLog(@"1111");"

设置了相同的优先级 (DISPATCH_QUEUE_PRIORITY_DEFAULT)

和"

1
2
while (1) {
        sleep(0.5);

"

将被添加到同一个目标队列中。结果,我可以假设在第一种情况下,带有 WHILE 的块将首先执行,并且因为它永远不会完成,所以队列中的下一个任务(NSLog(...))将永远不会被调用。

您可以尝试为队列使用不同的优先级 (DISPATCH_QUEUE_PRIORITY_LOW f.e.)。