串行队列上dispatch_async和dispatch_sync之间的区别?

时间:2013-11-06 20:59:21

标签: ios multithreading grand-central-dispatch

我创建了一个这样的串行队列:

    dispatch_queue_t _serialQueue = dispatch_queue_create("com.example.name", DISPATCH_QUEUE_SERIAL);

dispatch_async之间的区别是什么?

 dispatch_async(_serialQueue, ^{ /* TASK 1 */ });
 dispatch_async(_serialQueue, ^{ /* TASK 2 */ });

并且dispatch_sync在这个串行队列中调用了这个?

 dispatch_sync(_serialQueue, ^{ /* TASK 1 */ });
 dispatch_sync(_serialQueue, ^{ /* TASK 2 */ });

我的理解是,无论使用哪种调度方法,TASK 1都会在TASK 2之前执行并完成,是吗?

3 个答案:

答案 0 :(得分:393)

是。使用串行队列可确保任务的串行执行。唯一的区别是dispatch_sync仅在块完成后返回,而dispatch_async在添加到队列后返回并且可能没有完成。

代码

dispatch_async(_serialQueue, ^{ printf("1"); });
printf("2");
dispatch_async(_serialQueue, ^{ printf("3"); });
printf("4");

它可能会在2413之前打印2143123413

代码

dispatch_sync(_serialQueue, ^{ printf("1"); });
printf("2");
dispatch_sync(_serialQueue, ^{ printf("3"); });
printf("4");

始终打印1234


注意:对于第一个代码,不会打印1324。因为 printf("3")执行后会调度 {em}。 分派后,只能执行任务。


任务的执行时间不会改变任何事情。此代码始终打印printf("2")

12

可能发生的事情是

  • 线程1:dispatch_async一个耗时的任务(任务1)到串行队列
  • 线程2:开始执行任务1
  • 线程1:dispatch_async另一个任务(任务2)到串行队列
  • 主题2:任务1完成。开始执行任务2
  • 主题2:任务2完成。

你总是看到dispatch_async(_serialQueue, ^{ sleep(1000);printf("1"); }); dispatch_async(_serialQueue, ^{ printf("2"); });

答案 1 :(得分:18)

dispatch_syncdispatch_async之间的区别很简单。

在您的两个示例中,TASK 1将始终在TASK 2之前执行,因为它已在之前发送。

但是,在dispatch_sync示例中,在{em>分发并执行之后,您才会发送TASK 2。这称为"blocking"。您的代码等待(或“阻止”),直到任务执行。

TASK 1示例中,您的代码不会等待执行完成。两个块都将分派(并入队)到队列中,其余代码将继续在该线程上执行。然后在将来的某个时刻,(取决于已分配到队列中的其他内容),dispatch_async将执行,然后Task 1将执行。

答案 2 :(得分:3)

所有与主队列有关。有4个排列。

i)串行队列,分派异步:这里任务将一个接一个地执行,但是主线程(对UI起作用)不会等待返回

ii)串行队列,调度同步:这里的任务将一个接一个地执行,但主线程(UI上的效果)将显示延迟

iii)并发队列,分派异步:在这里任务将并行执行,并且主线程(UI上的效果)将不等待返回,并且将保持平稳。

iv)并发队列,调度同步:这里任务将并行执行,但是主线程(UI上的效果)将显示滞后

您对并发队列或串行队列的选择取决于您是否需要下一个任务的上一个任务的输出。如果您依赖于上一个任务,则采用串行队列,否则采用并发队列。

最后,当我们完成业务时,这是一种渗透回主线程的方法:

DispatchQueue.main.async {
     // Do something here
}