ChatGPT解决这个技术问题 Extra ChatGPT

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

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

    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之前执行并完成,对吗?


B
Bryan Chen

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

对于此代码

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

它可以打印 2413214312341 总是在 3 之前

对于此代码

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

它总是打印 1234

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

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

dispatch_async(_serialQueue, ^{ sleep(1000);printf("1"); });
dispatch_async(_serialQueue, ^{ printf("2"); });

可能发生的是

线程 1:dispatch_async 一个耗时的任务(任务 1)到串行队列

线程2:开始执行任务1

线程 1:dispatch_async 另一个任务(任务 2)到串行队列

线程 2:任务 1 完成。开始执行任务 2

线程 2:任务 2 完成。

你总是会看到12


它还可以打印 2134 和 1243
我的问题是为什么我们不像正常的方式那样做呢? printf("1");printf("2") ;printf("3") ;printf("4") - 与 dispatch_sync 相比
@androniennn 第二个例子?因为其他一些线程可能同时运行 dispatch_sync(_serialQueue, ^{ /*change shared data*/ });
@asma22 在多个线程/调度队列之间共享一个非线程安全的对象非常有用。如果您只访问串行队列中的对象,您就知道您正在安全地访问它。
我的意思是串行执行。就同一队列中的其他任务而言,所有任务都是串行执行的。当然,它仍然可以与其他队列并发。任务可以同时调度和执行是 GCD 的重点。
J
JRG-Developer

dispatch_syncdispatch_async 之间的区别很简单。

在您的两个示例中,TASK 1 将始终在 TASK 2 之前执行,因为它是在它之前分派的。

但是,在 dispatch_sync 示例中,直到 TASK 1 被调度并执行之后,您才会调度 TASK 2。这称为 "blocking"。您的代码等待(或“阻塞”)直到任务执行。

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


我认为您的订单错误。第一个示例是 async,它是非阻塞版本
我已经编辑了您对我认为您的意思的回答。如果不是这种情况,请更改并澄清。
如果你在同一个队列上调用 dispatch_sync 然后 dispatch_async 怎么办? (反之亦然)
在串行队列上,两个任务仍然一个接一个地执行。在第一种情况下,调用者等待第一个块完成但不等待第二个块。在第二种情况下,调用者不等待第一个块完成,而是等待第二个块。但由于队列按顺序执行块,调用者有效地等待两者完成。
块也可以在自己的队列上执行 dispatch_async(添加稍后将执行的更多块); dispatch_sync 在自己的串行队列或主队列上会死锁。在这种情况下,调用者将等待原始块完成,而不是等待其他块。请记住:dispatch_sync 将块放在队列的末尾,队列执行代码直到该块完成,然后 dispatch_sync 返回。 dispatch_async 只是在队列末尾添加块。
r
rd_

这都与主队列有关。有4个排列。

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

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

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

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

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

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

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

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅