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

Ios 串行队列上的dispatch_async和dispatch_sync之间的区别?,ios,multithreading,grand-central-dispatch,Ios,Multithreading,Grand Central Dispatch,我创建了一个串行队列,如下所示: dispatch_queue_t _serialQueue = dispatch_queue_create("com.example.name", DISPATCH_QUEUE_SERIAL); 像这样调用dispatch\u async有什么区别 dispatch_async(_serialQueue, ^{ /* TASK 1 */ }); dispatch_async(_serialQueue, ^{ /* TASK 2 */ }); 在这

我创建了一个串行队列,如下所示:

    dispatch_queue_t _serialQueue = dispatch_queue_create("com.example.name", DISPATCH_QUEUE_SERIAL);
像这样调用
dispatch\u async
有什么区别

 dispatch_async(_serialQueue, ^{ /* TASK 1 */ });
 dispatch_async(_serialQueue, ^{ /* TASK 2 */ });
在这个串行队列上这样调用
dispatch\u sync

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

我的理解是,无论使用哪种分派方法,
任务1
将在
任务2
之前执行并完成,对吗?

是。使用串行队列确保任务的串行执行。唯一的区别是
dispatch\u sync
仅在块完成后返回,而
dispatch\u async
在将其添加到队列中后返回,并且可能未完成

对于此代码

dispatch_async(_serialQueue, ^{ printf("1"); });
printf("2");
dispatch_async(_serialQueue, ^{ printf("3"); });
printf("4");
dispatch_sync(_serialQueue, ^{ printf("1"); });
printf("2");
dispatch_sync(_serialQueue, ^{ printf("3"); });
printf("4");
它可以打印
2413
2143
1234
,但
1
总是在
3

对于此代码

dispatch_async(_serialQueue, ^{ printf("1"); });
printf("2");
dispatch_async(_serialQueue, ^{ printf("3"); });
printf("4");
dispatch_sync(_serialQueue, ^{ printf("1"); });
printf("2");
dispatch_sync(_serialQueue, ^{ printf("3"); });
printf("4");
它总是打印
1234


注意:对于第一个代码,它不会打印
1324
。因为在执行
printf(“2”)
之后调度
printf(“3”)
。任务只有在被调度后才能执行


任务的执行时间不会改变任何东西。此代码始终打印
12

dispatch_async(_serialQueue, ^{ sleep(1000);printf("1"); });
dispatch_async(_serialQueue, ^{ printf("2"); });
可能发生的是

  • 线程1:将耗时的任务(任务1)异步分派到串行队列
  • 线程2:开始执行任务1
  • 线程1:将另一个任务(任务2)分派到串行队列
  • 线程2:任务1已完成。开始执行任务2
  • 线程2:任务2已完成

您总是可以看到
12

调度同步与
调度异步之间的区别很简单

dispatch_async(_serialQueue, ^{ sleep(1000);printf("1"); });
dispatch_async(_serialQueue, ^{ printf("2"); });
在这两个示例中,
TASK 1
将始终在
TASK 2
之前执行,因为它是在它之前调度的

但是,在
dispatch\u sync
示例中,只有在
TASK 1
被分派并执行之后,才能分派
TASK 2
。这就是所谓的。代码等待(或“阻塞”)直到任务执行


dispatch\u async
示例中,代码不会等待执行完成。这两个块都将分派(并排队)到队列,其余代码将继续在该线程上执行。然后在将来的某个时间点(取决于发送到队列的其他任务),
task1
将执行,然后
task2
将执行。

这一切都与主队列相关。有4种排列

i) 串行队列,异步调度:在这里,任务将一个接一个地执行,但主线程(对UI的影响)不会等待返回

ii)串行队列,调度同步:此处任务将一个接一个地执行,但主线程(对UI的影响)将显示滞后

iii)并发队列,异步调度:在这里,任务将并行执行,主线程(对UI的影响)不会等待返回,并且将是平滑的

iv)并发队列,调度同步:此处任务将并行执行,但主线程(对UI的影响)将显示滞后

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

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

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

我想你点错菜了。第一个例子是
async
,这是一个非阻塞版本,我已经编辑了你的答案,我认为你的意思是什么。如果不是这样,请更改并澄清。如果调用dispatch\u sync,然后在同一队列上调用dispatch\u async,会怎么样?(反之亦然)在串行队列上,这两个任务仍然一个接一个地执行。在第一种情况下,调用方等待第一个块完成,但不等待第二个块。在第二种情况下,调用方不等待第一个块完成,而是等待第二个块完成。但是,由于队列按顺序执行块,调用方有效地等待这两个块完成。块也可以在其自己的队列上执行异步调度(添加稍后将执行的其他块);在自己的串行队列或主队列上调度同步将死锁。在这种情况下,调用方将等待原始块完成,而不是等待其他块完成。请记住:dispatch_sync将块放在队列的末尾,队列执行代码直到该块完成,然后dispatch_sync返回。dispatch_async只在队列的末尾添加块。它还可以打印2134和1243M。我的问题是,我们为什么不按常规方式执行<代码>打印F(“1”);printf(“2”);printf(“3”);printf(“4”)
-与第二个示例中的调度同步相比?因为其他一些线程可能正在运行
dispatch\u sync(\u serialQueue,^{/*change shared data*/})同时。@asma22在多个线程/调度队列之间共享非线程安全对象非常有用。如果您只访问串行队列中的对象,您就知道您正在安全地访问它。我指的是串行执行。从一个角度来看,所有任务都是相对于同一队列中的其他任务串行执行的。当然,就其他队列而言,它仍然可以是并发的。GCD的核心是可以并发地调度和执行任务。