GCD中線程阻塞

隊(duì)列:
存放任務(wù)的地方,可以理解為存放一段一段要執(zhí)行的代碼。

線程:
執(zhí)行任務(wù)的流程。執(zhí)行完A,接著執(zhí)行B,然后再執(zhí)行C。

任務(wù)的執(zhí)行過程

同步派發(fā)必然會(huì)導(dǎo)致當(dāng)前線程被阻塞住,和隊(duì)列無關(guān)。派發(fā)函數(shù)必須等待任務(wù)完成才能返回。

用同步函數(shù)往并發(fā)隊(duì)列派發(fā)任務(wù)時(shí):
任務(wù)會(huì)當(dāng)前線程執(zhí)行。

用同步函數(shù)往串行隊(duì)列派發(fā)任務(wù)時(shí):
只要調(diào)用派發(fā)函數(shù)時(shí)不是在同一串行隊(duì)列中,就不會(huì)阻塞,任務(wù)會(huì)在當(dāng)前線程一個(gè)一個(gè)串行執(zhí)行,然后派發(fā)函數(shù)返回。

而異步派發(fā)函數(shù)比較神奇,不用等待任務(wù)完成就可直接返回,因此即使在串行隊(duì)列中向同一隊(duì)列異步派發(fā)任務(wù),也不會(huì)造成死鎖,因?yàn)榕砂l(fā)函數(shù)直接就返回了,串行隊(duì)列中靠后的任務(wù)就可以得以執(zhí)行。至于并發(fā)隊(duì)列,各個(gè)任務(wù)直接本來就是并發(fā)執(zhí)行的,不存在誰等待誰完成的問題。


同步:
 dispatch_queue_t queue = dispatch_queue_create("thread", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        NSLog(@"test1");
    });
    dispatch_sync(queue, ^{
        void(^bb)() = ^() {
            sleep(2);
            NSLog(@"延時(shí)");
        };
        bb();
        NSLog(@"test2");
    });
    dispatch_sync(queue, ^{
        NSLog(@"test3");
    });
    
    dispatch_barrier_sync(queue, ^{
        //此處耗時(shí),同步因此可能造成卡頓情況
      
        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");
    });

控制臺(tái)輸出:

2018-01-24 10:57:09.654 GCDDemo[3914:3750273] test1
2018-01-24 10:57:11.654 GCDDemo[3914:3750273] 延時(shí)
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

根據(jù)打印時(shí)間可以看到是同步執(zhí)行的,同步的好處是可控制性強(qiáng),一定是執(zhí)行完了才往下走,缺點(diǎn)就是如果某一個(gè)函數(shù)比較耗時(shí)的話(此處是手動(dòng)延時(shí)2秒),就會(huì)阻塞該線程的執(zhí)行。


接下來再看dispatch_barrier_syncdispatch_barrier_async
dispatch_barrier_syncdispatch_sync效果幾乎一樣,順步執(zhí)行。
打開上面注釋掉的dispatch_barrier_sync,運(yùn)行,打印結(jié)果如下。

2018-01-25 09:56:38.473 GCDDemo[1671:973161] test1
2018-01-25 09:56:40.474 GCDDemo[1671:973161] 延時(shí)
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

可以看到打印結(jié)果的順序并沒有發(fā)生變化。
如果把dispatch_barrier_sync換成dispatch_barrier_async呢?打印結(jié)果如下:

2018-01-25 10:22:58.407 GCDDemo[1719:1045532] test1
2018-01-25 10:23:00.408 GCDDemo[1719:1045532] 延時(shí)
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

可以看出,程序執(zhí)行到dispatch_barrier_async的時(shí)候,沒有等待結(jié)果返回,直接往下執(zhí)行,直到遇到dispatch_sync,才會(huì)等待dispatch_barrier_async返回結(jié)果,再次繼續(xù)往下執(zhí)行。



    /**
     異步進(jìn)程
     test1,2,3,不阻塞線程,并不確定哪個(gè)會(huì)先執(zhí)行完.
     
     */
    dispatch_queue_t queue = dispatch_queue_create("thread", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"test1");
    });
    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"延時(shí)");
        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] 延時(shí)
2018-01-24 11:11:31.324 GCDDemo[4002:3837525] test2

可以看到異步的時(shí)候,每一個(gè)進(jìn)程執(zhí)行相互是不影響的。這種模式比較常見的就是網(wǎng)絡(luò)解析圖片的時(shí)候,異步解析,主線程加載圖片。不阻塞線程,但是還有一個(gè)問題就是,程序可控性較差,有時(shí)候可能得不到結(jié)果。比如C要獲得到A的結(jié)果才能正常執(zhí)行,但是A還沒有執(zhí)行完畢的時(shí)候,C可能就執(zhí)行了。

  1. 再來看dispatch_barrier_async,打開上面的注釋,看一下打印結(jié)果:
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] 延時(shí)
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

可以看出代碼執(zhí)行不受影響,不用等待其他代碼執(zhí)行完成,各走各的。

  1. 換成dispatch_barrier_sync,再看一下打印結(jié)果
2018-01-25 14:57:29.253 GCDDemo[2189:1798062] test1
2018-01-25 14:57:29.254 GCDDemo[2189:1798689] 延時(shí)
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中的代碼執(zhí)行完畢才能執(zhí)行。


dispatch_barrier_async 和 dispatch_barrier_sync區(qū)別
總結(jié):
簡單來說,就是asyn不阻塞當(dāng)前線程而已,barrier只是阻塞同隊(duì)列中后面的操作而已
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容