是否GCD dispatch_async在NSLog()上等待?

时间:2011-12-15 19:56:55

标签: ios cocoa concurrency grand-central-dispatch nslog

从我所读到的关于Grand Central Dispatch的内容来看,GCD并不进行抢占式多任务处理;它只是一个单一的事件循环。我无法理解这个输出。我有两个队列只做一些输出(起初我正在读/写一些共享状态,但我能够简化到这个并仍然得到相同的结果)。

dispatch_queue_t authQueue = dispatch_queue_create("authQueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t authQueue2 = dispatch_queue_create("authQueue", DISPATCH_QUEUE_SERIAL);

dispatch_async(authQueue, ^{ 
    NSLog(@"First Block");
    NSLog(@"First Block Incrementing"); 
    NSLog(@"First Block Incremented"); 
});

dispatch_async(authQueue, ^{ 
    NSLog(@"Second Block");
    NSLog(@"Second Block Incrementing");
    NSLog(@"Second Block Incremented"); 
});

dispatch_async(authQueue2,^{ 
    NSLog(@"Third Block"); 
    NSLog(@"Third Block Incrementing");
    NSLog(@"Third Block Incremented"); 
});

我得到以下输出:

2011-12-15 13:47:17.746 App[80376:5d03] Third Block
2011-12-15 13:47:17.746 App[80376:1503] First Block
2011-12-15 13:47:17.746 App[80376:5d03] Third Block Incrementing
2011-12-15 13:47:17.746 App[80376:1503] First Block Incrementing
2011-12-15 13:47:17.748 App[80376:1503] First Block Incremented
2011-12-15 13:47:17.748 App[80376:5d03] Third Block Incremented
2011-12-15 13:47:17.750 App[80376:1503] Second Block
2011-12-15 13:47:17.750 App[80376:1503] Second Block Incrementing
2011-12-15 13:47:17.751 App[80376:1503] Second Block Incremented

很明显,这些块不会以原子方式执行。我唯一的理论是GCD通过NSLog写入stdio会使当前执行等待。我在Apple文档中找不到与此相关的任何内容。谁能解释一下呢?

4 个答案:

答案 0 :(得分:8)

GCD不使用任何类型的“事件循环”。它是Mac OS X和iOS最新版本中的一个新内核功能,它实际上没有我所知道的任何其他类似技术。

目标是完成执行您提供的所有代码,就像硬件允许的那样快。请注意,它的目标是最快的完成时间,而不是最快的开始时间。这是一个微妙的差异,但却是一个重要的差异,它会影响它的工作原理。

如果你只有一个空闲的CPU核心,那么理论上一次只能执行其中一个核心。因为单个内核中的多任务比顺序执行两个任务要慢。但实际情况并非如此。如果CPU核心暂时变得空闲或者不是很忙(例如,读取硬盘驱动器,或等待其他程序响应(Xcode绘制NSLog输出)),那么它很可能会继续执行一秒钟GCD项目,因为它正在进行的项目被卡住了。

当然,大多数情况下拥有多个空闲CPU核心。

它也不一定按照你给出的确切顺序执行。 GCD /内核可以控制这些细节。

对于您的特定示例,Xcode的调试器可能一次只能处理单个NSLog()事件(至少,它必须一次绘制一个屏幕)。你有两个队列,他们可能会同时开始执行。如果您一次发送两个NSLog()语句,其中一个语句将等待另一个语句完成。因为除了向Xcode打印东西之外你没有做任何事情,这两个GCD队列将成为第一个将日志数据发送到Xcode的竞赛。第一个有一个轻微的开头,但它是一个非常轻微的,并且通常不足以首先打开与Xcode的连接。

这完全取决于特定纳秒时间硬件上可用的实际硬件资源。你无法预测它,需要适当地构建你的队列以承担一些控制。

答案 1 :(得分:2)

你在哪里读到GCD没有先发制人的多任务处理?我觉得你错了。它建立在系统提供的线程支持之上,因此派遣到队列的GCD块可能会被抢先中断。

您所看到的行为正是我所期待的。第一个和第二个块被分派到同一个队列,因此GCD将确保第一个块在第二个块开始之前完成。但是,块3被分派到一个完全不同的队列(即将在一个单独的后台线程上运行),因此当系统调度线程时,它的输出与其他两个块交错。

答案 2 :(得分:2)

除非您使用串行调度队列,否则您读取的内容都是错误的,所有块都将同时执行。

答案 3 :(得分:0)

您的队列在2个并发后台线程中工作。它们同时提供NSLog消息。当一个线程产生NSlog输出时,另一个线程等待 怎么了?