队列:
存放任务的地方,可以理解为存放一段一段要执行的代码。
线程:
执行任务的流程。执行完A,接着执行B,然后再执行C。
任务的执行过程
同步派发必然会导致当前线程被阻塞住,和队列无关。派发函数必须等待任务完成才能返回。
用同步函数往并发队列派发任务时:
任务会当前线程执行。
用同步函数往串行队列派发任务时:
只要调用派发函数时不是在同一串行队列中,就不会阻塞,任务会在当前线程一个一个串行执行,然后派发函数返回。
而异步派发函数比较神奇,不用等待任务完成就可直接返回,因此即使在串行队列中向同一队列异步派发任务,也不会造成死锁,因为派发函数直接就返回了,串行队列中靠后的任务就可以得以执行。至于并发队列,各个任务直接本来就是并发执行的,不存在谁等待谁完成的问题。
同步:
dispatch_queue_t queue = dispatch_queue_create("thread", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
NSLog(@"test1");
});
dispatch_sync(queue, ^{
void(^bb)() = ^() {
sleep(2);
NSLog(@"延时");
};
bb();
NSLog(@"test2");
});
dispatch_sync(queue, ^{
NSLog(@"test3");
});
dispatch_barrier_sync(queue, ^{
//此处耗时,同步因此可能造成卡顿情况
for (NSInteger i = 0; i < 500000000; i++) {
if (i == 500000)NSLog(@"point1");
if (i == 600000)NSLog(@"point2");
if (i == 700000)NSLog(@"point3");
}
NSLog(@"barrier");
});
NSLog(@"aaa");
dispatch_sync(queue, ^{
NSLog(@"test4");
});
NSLog(@"bbb");
dispatch_sync(queue, ^{
NSLog(@"test5");
});
dispatch_sync(queue, ^{
NSLog(@"test6");
});
控制台输出:
2018-01-24 10:57:09.654 GCDDemo[3914:3750273] test1
2018-01-24 10:57:11.654 GCDDemo[3914:3750273] 延时
2018-01-24 10:57:11.654 GCDDemo[3914:3750273] test2
2018-01-24 10:57:11.655 GCDDemo[3914:3750273] test3
2018-01-24 10:57:12.868 GCDDemo[3914:3750273] aaa
2018-01-24 10:57:12.868 GCDDemo[3914:3750273] test4
2018-01-24 10:57:12.868 GCDDemo[3914:3750273] bbb
2018-01-24 10:57:12.868 GCDDemo[3914:3750273] test5
2018-01-24 10:57:12.869 GCDDemo[3914:3750273] test6
根据打印时间可以看到是同步执行的,同步的好处是可控制性强,一定是执行完了才往下走,缺点就是如果某一个函数比较耗时的话(此处是手动延时2秒),就会阻塞该线程的执行。
接下来再看dispatch_barrier_sync
和 dispatch_barrier_async
dispatch_barrier_sync
跟dispatch_sync
效果几乎一样,顺步执行。
打开上面注释掉的dispatch_barrier_sync
,运行,打印结果如下。
2018-01-25 09:56:38.473 GCDDemo[1671:973161] test1
2018-01-25 09:56:40.474 GCDDemo[1671:973161] 延时
2018-01-25 09:56:40.474 GCDDemo[1671:973161] test2
2018-01-25 09:56:40.474 GCDDemo[1671:973161] test3
2018-01-25 09:56:40.476 GCDDemo[1671:973161] point1
2018-01-25 09:56:40.476 GCDDemo[1671:973161] point2
2018-01-25 09:56:40.476 GCDDemo[1671:973161] point3
2018-01-25 09:56:41.650 GCDDemo[1671:973161] barrier
2018-01-25 09:56:41.650 GCDDemo[1671:973161] aaa
2018-01-25 09:56:41.650 GCDDemo[1671:973161] test4
2018-01-25 09:56:41.650 GCDDemo[1671:973161] bbb
2018-01-25 09:56:41.650 GCDDemo[1671:973161] test5
2018-01-25 09:56:41.650 GCDDemo[1671:973161] test6
可以看到打印结果的顺序并没有发生变化。
如果把dispatch_barrier_sync
换成dispatch_barrier_async
呢?打印结果如下:
2018-01-25 10:22:58.407 GCDDemo[1719:1045532] test1
2018-01-25 10:23:00.408 GCDDemo[1719:1045532] 延时
2018-01-25 10:23:00.408 GCDDemo[1719:1045532] test2
2018-01-25 10:23:00.408 GCDDemo[1719:1045532] test3
2018-01-25 10:23:00.408 GCDDemo[1719:1045532] aaa
2018-01-25 10:23:00.410 GCDDemo[1719:1045691] point1
2018-01-25 10:23:00.410 GCDDemo[1719:1045691] point2
2018-01-25 10:23:00.410 GCDDemo[1719:1045691] point3
2018-01-25 10:23:01.597 GCDDemo[1719:1045691] barrier
2018-01-25 10:23:01.597 GCDDemo[1719:1045532] test4
2018-01-25 10:23:01.598 GCDDemo[1719:1045532] bbb
2018-01-25 10:23:01.598 GCDDemo[1719:1045532] test5
2018-01-25 10:23:01.598 GCDDemo[1719:1045532] test6
可以看出,程序执行到dispatch_barrier_async
的时候,没有等待结果返回,直接往下执行,直到遇到dispatch_sync
,才会等待dispatch_barrier_async
返回结果,再次继续往下执行。
/**
异步进程
test1,2,3,不阻塞线程,并不确定哪个会先执行完.
*/
dispatch_queue_t queue = dispatch_queue_create("thread", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"test1");
});
dispatch_async(queue, ^{
sleep(2);
NSLog(@"延时");
NSLog(@"test2");
});
dispatch_async(queue, ^{
NSLog(@"test3");
});
// dispatch_barrier_async(queue, ^{
// for (NSInteger i = 0; i < 500000000; i++) {
// if (i == 500000)NSLog(@"point1");
// if (i == 600000)NSLog(@"point2");
// if (i == 700000)NSLog(@"point3");
// }
// NSLog(@"barrier");
// });
NSLog(@"aaa");
dispatch_async(queue, ^{
NSLog(@"test4");
});
NSLog(@"bbb");
dispatch_async(queue, ^{
NSLog(@"test5");
});
dispatch_async(queue, ^{
NSLog(@"test6");
});
return;
dispatch_sync(queue, ^{
NSLog(@"1");
});
dispatch_sync(queue, ^{
NSLog(@"2");
});
dispatch_sync(queue, ^{
NSLog(@"3");
});
dispatch_sync(queue, ^{
NSLog(@"4");
});
2018-01-24 11:11:29.320 GCDDemo[4002:3827389] aaa
2018-01-24 11:11:29.320 GCDDemo[4002:3832535] test1
2018-01-24 11:11:29.320 GCDDemo[4002:3837535] test3
2018-01-24 11:11:29.320 GCDDemo[4002:3827389] bbb
2018-01-24 11:11:29.320 GCDDemo[4002:3837536] test4
2018-01-24 11:11:29.321 GCDDemo[4002:3837535] test5
2018-01-24 11:11:29.321 GCDDemo[4002:3832535] test6
2018-01-24 11:11:31.324 GCDDemo[4002:3837525] 延时
2018-01-24 11:11:31.324 GCDDemo[4002:3837525] test2
可以看到异步的时候,每一个进程执行相互是不影响的。这种模式比较常见的就是网络解析图片的时候,异步解析,主线程加载图片。不阻塞线程,但是还有一个问题就是,程序可控性较差,有时候可能得不到结果。比如C要获得到A的结果才能正常执行,但是A还没有执行完毕的时候,C可能就执行了。
- 再来看
dispatch_barrier_async
,打开上面的注释,看一下打印结果:
2018-01-25 10:44:03.021 GCDDemo[1767:1097902] aaa
2018-01-25 10:44:03.021 GCDDemo[1767:1100068] test1
2018-01-25 10:44:03.021 GCDDemo[1767:1100069] test3
2018-01-25 10:44:03.021 GCDDemo[1767:1097902] bbb
2018-01-25 10:44:05.024 GCDDemo[1767:1098660] 延时
2018-01-25 10:44:05.024 GCDDemo[1767:1098660] test2
2018-01-25 10:44:05.026 GCDDemo[1767:1098660] point1
2018-01-25 10:44:05.026 GCDDemo[1767:1098660] point2
2018-01-25 10:44:05.026 GCDDemo[1767:1098660] point3
2018-01-25 10:44:06.300 GCDDemo[1767:1098660] barrier
2018-01-25 10:44:06.300 GCDDemo[1767:1100069] test4
2018-01-25 10:44:06.300 GCDDemo[1767:1100068] test5
2018-01-25 10:44:06.300 GCDDemo[1767:1100068] test6
可以看出代码执行不受影响,不用等待其他代码执行完成,各走各的。
- 换成
dispatch_barrier_sync
,再看一下打印结果
2018-01-25 14:57:29.253 GCDDemo[2189:1798062] test1
2018-01-25 14:57:29.254 GCDDemo[2189:1798689] 延时
2018-01-25 14:57:29.254 GCDDemo[2189:1798063] test3
2018-01-25 14:57:29.254 GCDDemo[2189:1798689] test2
2018-01-25 14:57:29.255 GCDDemo[2189:1796600] point1
2018-01-25 14:57:29.256 GCDDemo[2189:1796600] point2
2018-01-25 14:57:29.256 GCDDemo[2189:1796600] point3
2018-01-25 14:57:30.419 GCDDemo[2189:1796600] barrier
2018-01-25 14:57:30.420 GCDDemo[2189:1796600] aaa
2018-01-25 14:57:30.420 GCDDemo[2189:1796600] bbb
2018-01-25 14:57:30.420 GCDDemo[2189:1798689] test4
2018-01-25 14:57:30.420 GCDDemo[2189:1798689] test5
2018-01-25 14:57:30.420 GCDDemo[2189:1798063] test6
可以看出,在插入位置前面的代码,不受影响,各走各的,但是插入位置之后的,就必须等待dispatch_barrier_sync
中的代码执行完毕才能执行。
dispatch_barrier_async 和 dispatch_barrier_sync区别
总结:
简单来说,就是asyn不阻塞当前线程而已,barrier只是阻塞同队列中后面的操作而已