我创建了一个这样的串行队列:
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
之前执行并完成,对吗?
是的。使用串行队列保证任务的串行执行。唯一的区别是 dispatch_sync
仅在块完成后返回,而 dispatch_async
在将其添加到队列后返回并且可能未完成。
对于此代码
dispatch_async(_serialQueue, ^{ printf("1"); });
printf("2");
dispatch_async(_serialQueue, ^{ printf("3"); });
printf("4");
它可以打印 2413
或 2143
或 1234
但 1
总是在 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
dispatch_sync
和 dispatch_async
之间的区别很简单。
在您的两个示例中,TASK 1
将始终在 TASK 2
之前执行,因为它是在它之前分派的。
但是,在 dispatch_sync
示例中,直到 TASK 1
被调度并执行之后,您才会调度 TASK 2
。这称为 "blocking"。您的代码等待(或“阻塞”)直到任务执行。
在 dispatch_async
示例中,您的代码不会等待执行完成。两个块都将分派(并入队)到队列,其余代码将继续在该线程上执行。然后在将来的某个时间点(取决于已分派到您的队列的其他内容),Task 1
将执行,然后 Task 2
将执行。
async
,它是非阻塞版本
这都与主队列有关。有4个排列。
i) 串行队列,异步调度:这里任务将一个接一个地执行,但主线程(对 UI 的影响)不会等待返回
ii) 串行队列,调度同步:这里任务将一个接一个地执行,但主线程(对 UI 的影响)会显示滞后
iii) 并发队列,异步调度:这里任务将并行执行,主线程(对 UI 的影响)不会等待返回,并且会很流畅。
iv) 并发队列,调度同步:这里任务将并行执行,但主线程(对 UI 的影响)会显示滞后
您选择并发队列还是串行队列取决于您是否需要前一个任务的输出用于下一个任务。如果依赖上一个任务,则采用串行队列,否则采用并发队列。
最后,当我们完成业务时,这是一种回到主线程的方式:
DispatchQueue.main.async {
// Do something here
}
printf("1");printf("2") ;printf("3") ;printf("4")
- 与dispatch_sync
相比dispatch_sync(_serialQueue, ^{ /*change shared data*/ });
。