浅谈dispatch_barrier_(a)sync

最近在使用dispatch_barrier_async时踩到了坑,随即仔细了解了一下dispatch_barrier_async,发现了不少有意思的事情,下面且听我一一道来。

平常的开发过程中,应该有不少童鞋遇到过这样的需求:分别有三个异步任务A、B、C,要求任务A、B全部执行完毕之后才执行C;面对这个需求,Dispatch Group是很多人的选择,而为了追求更简便的操作,dispatch_barrier_async应该更受青睐。
好了,既然决定使用dispatch_barrier_async,那么来吧,说干就干,很简单的几行代码,马上写出来了:

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSLog(@"任务A");
    });
    dispatch_async(queue, ^{
        NSLog(@"任务B");
    });
    dispatch_barrier_async(queue, ^{
        NSLog(@"任务C");
    });

好了,美滋滋的喝口饮料,等待程序执行;这么简单的东西,还能出错?搞笑呢是吧!哼哼,等着看吧,肯定是打印A、B后,最后打印出执行C。刚喝完一口饮料,看到打印结果,顿时喷了出来......

2018-03-17 15:19:16.231556+0800 dispatch_barriar_test[4274:331672] 任务C
2018-03-17 15:19:16.231569+0800 dispatch_barriar_test[4274:331836] 任务A
2018-03-17 15:19:16.231569+0800 dispatch_barriar_test[4274:331833] 任务B

啊?眼花了?编译器疯了?还是...我疯了?
看了下代码,创建并发队列,然后添加任务A、B,最后一个dispatch_barrier_async进行同步节点执行任务C,没问题啊,这怎么回事儿?跟想象的不一样,赶紧查了下该方法的官方注释,发现了一个“坑爹”的解释:



翻译过来的意思就是:
如果提交的是全局并发队列或未使用DISPATCH_QUEUE_CONCURRENT属性创建的队列(意即创建了一个串行队列)时,dispatch_barrier 与dispatch_async()/ dispatch_sync()API提交的block的行为相同。
也就是使用dispatch_barrier时,是不能使用dispatch_get_global_queue的,赶紧换成dispatch_queue_create创建一个并发队列,如下:

    dispatch_queue_t queue = dispatch_queue_create("Test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"任务A");
    });
    dispatch_async(queue, ^{
        NSLog(@"任务B");
    });
    dispatch_barrier_async(queue, ^{
        NSLog(@"任务C");
    });

这下正常了,不经意的一个小问题,导致大问题的出现,谨记谨记。

查看官方文档时候,发现了dispatch_barrier_async和dispatch_barrier_sync两个方法,以前只是使用过dispatch_barrier_async方法,而dispatch_barrier_sync却比较陌生,于是比较了两个方法的功能,又有了新的发现。

首先使用dispatch_barrier_async进行测试

    dispatch_queue_t queue = dispatch_queue_create("Test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"任务1");
    });
    dispatch_async(queue, ^{
        NSLog(@"任务2");
    });
    dispatch_barrier_async(queue, ^{
        sleep(3);
        NSLog(@"barrier");
    });
    dispatch_async(queue, ^{
        NSLog(@"任务4");
    });

打印结果如下:

2018-03-17 15:40:18.736130+0800 dispatch_barriar_test[4542:365066] 任务2
2018-03-17 15:40:18.736130+0800 dispatch_barriar_test[4542:365062] 任务1
2018-03-17 15:40:21.737863+0800 dispatch_barriar_test[4542:365062] barrier
2018-03-17 15:40:21.738172+0800 dispatch_barriar_test[4542:365062] 任务4

然后使用dispatch_barrier_sync测试

    dispatch_queue_t queue = dispatch_queue_create("Test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"任务1");
    });
    dispatch_async(queue, ^{
        NSLog(@"任务2");
    });
    dispatch_barrier_sync(queue, ^{
        sleep(3);
        NSLog(@"barrier");
    });
    dispatch_async(queue, ^{
        NSLog(@"任务4");
    });

咦?怎么一样?难道两个没有区别?不会的,苹果怎么可能给同一个API两个不同的名称?既然不同肯定有区别。接着实验,还是先实验dispatch_barrier_async:

    dispatch_queue_t queue = dispatch_queue_create("Test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"任务1");
    });
    dispatch_async(queue, ^{
        NSLog(@"任务2");
    });
    dispatch_barrier_async(queue, ^{
        sleep(3);
        NSLog(@"barrier");
    });
    NSLog(@"来到了这里");
    dispatch_async(queue, ^{
        NSLog(@"任务4");
    });

打印结果(注意NSLog(@"来到了这里");这行代码的执行):

2018-03-17 15:45:08.918462+0800 dispatch_barriar_test[4647:374019] 任务1
2018-03-17 15:45:08.918462+0800 dispatch_barriar_test[4647:373957] 来到了这里
2018-03-17 15:45:08.918462+0800 dispatch_barriar_test[4647:374023] 任务2
2018-03-17 15:45:11.919786+0800 dispatch_barriar_test[4647:374023] barrier
2018-03-17 15:45:11.920103+0800 dispatch_barriar_test[4647:374023] 任务4

接着实验dispatch_barrier_sync:

    dispatch_queue_t queue = dispatch_queue_create("Test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"任务1");
    });
    dispatch_async(queue, ^{
        NSLog(@"任务2");
    });
    dispatch_barrier_sync(queue, ^{
        sleep(3);
        NSLog(@"barrier");
    });
    NSLog(@"来到了这里");
    dispatch_async(queue, ^{
        NSLog(@"任务4");
    });

打印结果:

2018-03-17 15:48:13.325138+0800 dispatch_barriar_test[4714:380014] 任务1
2018-03-17 15:48:13.325141+0800 dispatch_barriar_test[4714:380011] 任务2
2018-03-17 15:48:16.325626+0800 dispatch_barriar_test[4714:379926] barrier
2018-03-17 15:48:16.325873+0800 dispatch_barriar_test[4714:379926] 来到了这里
2018-03-17 15:48:16.326083+0800 dispatch_barriar_test[4714:380011] 任务4

区别来了,"来到了这里"这句话执行时机不同,async不会阻塞主线程后面的代码执行,而sync则是会将本身block中的任务执行完毕后,程序才会接着执行sync之后的代码。总结如下:
dispatch_barrier_sync和dispatch_barrier_async的共同点:
1、都会等待在它前面插入队列的任务(A、B)先执行完
2、都会等待他们自己的任务(barrier)执行完再执行后面的任务(C)
dispatch_barrier_sync和dispatch_barrier_async的不共同点:
在将任务插入到queue的时候,dispatch_barrier_sync需要等待自己的任务(barrier)结束之后才会继续程序,然后插入被写在它后面的任务(C),然后执行任务(C)
而dispatch_barrier_async将自己的任务(barrier)插入到queue之后,不会等待自己的任务结束,程序继续执行,会继续把后面的任务(C)插入到queue。
所以,dispatch_barrier_async的不等待(异步)特性体现在将任务插入队列的过程,它的等待特性体现在任务真正执行的过程。

附录(也算是追加)

也许会对并行、串行、异步、同步有所理解不深。
并行:就是队列里面的任务(代码块,block)不是一个个执行,而是并发执行,也就是可以同时执行的意思
串行:队列里面的任务一个接着一个执行,要等前一个任务结束,下一个任务才可以执行
异步:具有新开线程的能力
同步:不具有新开线程的能力,只能在当前线程执行任务

那么,如果他们相互串起来,会怎么样呢?
并行+异步:就是真正的并发,新开有有多个线程处理任务,任务并发执行(不按顺序执行)
串行+异步:新开一个线程,任务一个接一个执行,上一个任务处理完毕,下一个任务才可以被执行
并行+同步:不新开线程,任务一个接一个执行
串行+同步:不新开线程,任务一个接一个执行

参考文献:https://www.cnblogs.com/ziyi--caolu/p/4900650.html
http://blog.csdn.net/u013046795/article/details/47057585

?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351

推荐阅读更多精彩内容