iOS多線(xiàn)程:GCD

1.GCD的概念

GCD為Grand Central Dispatch的縮寫(xiě)脆丁。
它主要用于優(yōu)化應(yīng)用程序以支持多核處理器以及其他對(duì)稱(chēng)多處理系統(tǒng)句喷。它是一個(gè)在線(xiàn)程池模式的基礎(chǔ)上執(zhí)行的并行任務(wù)丐膝。在Mac OS X 10.6雪豹中首次推出鞍历,也可在IOS 4及以上版本使用。

2.GCD的隊(duì)列和任務(wù)

GCD包括兩個(gè)核心概念:隊(duì)列任務(wù)

2.1隊(duì)列

隊(duì)列是一種特殊的線(xiàn)性表跨算,遵循FIFO(先進(jìn)先出)原則轻要,新添加的任務(wù)在隊(duì)尾,執(zhí)行任務(wù)的時(shí)候從隊(duì)首開(kāi)始讀取并執(zhí)行旱爆。隊(duì)列分為串行隊(duì)列并行隊(duì)列舀射,區(qū)別主要是:隊(duì)列中任務(wù)執(zhí)行的順序不同,開(kāi)啟的線(xiàn)程數(shù)也不同怀伦。

串行隊(duì)列

每個(gè)時(shí)間段只有一個(gè)任務(wù)在執(zhí)行脆烟,只開(kāi)啟一個(gè)線(xiàn)程,一個(gè)任務(wù)執(zhí)行完以后再執(zhí)行下一個(gè)任務(wù)房待。

并行隊(duì)列

可以有多個(gè)任務(wù)在并發(fā)執(zhí)行邢羔,可以開(kāi)啟多個(gè)線(xiàn)程同時(shí)處理多個(gè)任務(wù)。

2.2任務(wù)

任務(wù)就是需要執(zhí)行的一組操作桑孩,在GCD是放在block中的那一段代碼拜鹤,任務(wù)分為同步任務(wù)異步任務(wù),區(qū)別是:是否等待隊(duì)列的任務(wù)執(zhí)行結(jié)束流椒,以及是否具備開(kāi)啟新線(xiàn)程的能力敏簿。

同步sync

同步任務(wù)會(huì)等待操作執(zhí)行完畢,再執(zhí)行block外的操作镣隶,只能在當(dāng)前線(xiàn)程中執(zhí)行任務(wù)极谊。

異步async

異步任務(wù)不會(huì)等待操作執(zhí)行完畢,會(huì)直接繼續(xù)執(zhí)行block外的操作安岂,可以在開(kāi)啟新的線(xiàn)程執(zhí)行任務(wù)。

3.GCD的具體使用

3.1創(chuàng)建隊(duì)列

dispatch_queue_t serial_queue = dispatch_queue_create("serial_queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t concurrent_queue = dispatch_queue_create("concurrent_queue", DISPATCH_QUEUE_CONCURRENT);

3.2隊(duì)列和任務(wù)的簡(jiǎn)單組合

3.2.1串行+同步

//    串行隊(duì)列+同步
    NSLog(@"主流程start--%@", [NSThread currentThread]);
    dispatch_sync(serial_queue, ^{
        NSLog(@"同步1--操作1--%@", [NSThread currentThread]);
        sleep(3);
        NSLog(@"同步1--操作2--%@", [NSThread currentThread]);
    });
    dispatch_sync(serial_queue, ^{
        NSLog(@"同步2--操作1--%@", [NSThread currentThread]);
        sleep(1);
        NSLog(@"同步2--操作2--%@", [NSThread currentThread]);
    });
    dispatch_sync(serial_queue, ^{
        NSLog(@"同步3--操作1--%@", [NSThread currentThread]);
        sleep(2);
        NSLog(@"同步3--操作2--%@", [NSThread currentThread]);
    });
    NSLog(@"主流程end-----%@", [NSThread currentThread]);
2021-03-20 17:08:38.693421+0800 test1[8934:9017257] 主流程start--<NSThread: 0x60000102dd80>{number = 1, name = main}
2021-03-20 17:08:38.693566+0800 test1[8934:9017257] 同步1--操作1--<NSThread: 0x60000102dd80>{number = 1, name = main}
2021-03-20 17:08:41.694375+0800 test1[8934:9017257] 同步1--操作2--<NSThread: 0x60000102dd80>{number = 1, name = main}
2021-03-20 17:08:41.694603+0800 test1[8934:9017257] 同步2--操作1--<NSThread: 0x60000102dd80>{number = 1, name = main}
2021-03-20 17:08:42.695118+0800 test1[8934:9017257] 同步2--操作2--<NSThread: 0x60000102dd80>{number = 1, name = main}
2021-03-20 17:08:42.695589+0800 test1[8934:9017257] 同步3--操作1--<NSThread: 0x60000102dd80>{number = 1, name = main}
2021-03-20 17:08:44.696285+0800 test1[8934:9017257] 同步3--操作2--<NSThread: 0x60000102dd80>{number = 1, name = main}
2021-03-20 17:08:44.696645+0800 test1[8934:9017257] 主流程end-----<NSThread: 0x60000102dd80>{number = 1, name = main}

3.2.2并行+同步

//    并行隊(duì)列+同步
    NSLog(@"主流程start--%@", [NSThread currentThread]);
    dispatch_sync(concurrent_queue, ^{
        NSLog(@"同步1--操作1--%@", [NSThread currentThread]);
        sleep(3);
        NSLog(@"同步1--操作2--%@", [NSThread currentThread]);
    });
    dispatch_sync(concurrent_queue, ^{
        NSLog(@"同步2--操作1--%@", [NSThread currentThread]);
        sleep(1);
        NSLog(@"同步2--操作2--%@", [NSThread currentThread]);
    });
    dispatch_sync(concurrent_queue, ^{
        NSLog(@"同步3--操作1--%@", [NSThread currentThread]);
        sleep(2);
        NSLog(@"同步3--操作2--%@", [NSThread currentThread]);
    });
    NSLog(@"主流程end-----%@", [NSThread currentThread]);
2021-03-20 17:07:19.312244+0800 test1[8866:9015712] 主流程start--<NSThread: 0x600002961dc0>{number = 1, name = main}
2021-03-20 17:07:19.312456+0800 test1[8866:9015712] 同步1--操作1--<NSThread: 0x600002961dc0>{number = 1, name = main}
2021-03-20 17:07:22.313735+0800 test1[8866:9015712] 同步1--操作2--<NSThread: 0x600002961dc0>{number = 1, name = main}
2021-03-20 17:07:22.314070+0800 test1[8866:9015712] 同步2--操作1--<NSThread: 0x600002961dc0>{number = 1, name = main}
2021-03-20 17:07:23.315434+0800 test1[8866:9015712] 同步2--操作2--<NSThread: 0x600002961dc0>{number = 1, name = main}
2021-03-20 17:07:23.315738+0800 test1[8866:9015712] 同步3--操作1--<NSThread: 0x600002961dc0>{number = 1, name = main}
2021-03-20 17:07:25.317084+0800 test1[8866:9015712] 同步3--操作2--<NSThread: 0x600002961dc0>{number = 1, name = main}
2021-03-20 17:07:25.317458+0800 test1[8866:9015712] 主流程end-----<NSThread: 0x600002961dc0>{number = 1, name = main}

3.2.3串行+異步

//    串行隊(duì)列+異步
       NSLog(@"主流恒start--%@", [NSThread currentThread]);
    dispatch_async(serial_queue, ^{
        NSLog(@"異步1--操作1--%@", [NSThread currentThread]);
        sleep(3);
        NSLog(@"異步1--操作2--%@", [NSThread currentThread]);
    });
    dispatch_async(serial_queue, ^{
        NSLog(@"異步2--操作1--%@", [NSThread currentThread]);
        sleep(1);
        NSLog(@"異步2--操作2--%@", [NSThread currentThread]);
    });
    dispatch_async(serial_queue, ^{
        NSLog(@"異步3--操作1--%@", [NSThread currentThread]);
        sleep(2);
        NSLog(@"異步3--操作2--%@", [NSThread currentThread]);
    });
    NSLog(@"主流程end-----%@", [NSThread currentThread]);
2021-03-20 16:52:39.159286+0800 test1[8200:9002593] 主流恒start--<NSThread: 0x600002b2ab80>{number = 1, name = main}
2021-03-20 16:52:39.159443+0800 test1[8200:9002593] 主流程end-----<NSThread: 0x600002b2ab80>{number = 1, name = main}
2021-03-20 16:52:39.159462+0800 test1[8200:9002672] 異步1--操作1--<NSThread: 0x600002b42040>{number = 6, name = (null)}
2021-03-20 16:52:42.164330+0800 test1[8200:9002672] 異步1--操作2--<NSThread: 0x600002b42040>{number = 6, name = (null)}
2021-03-20 16:52:42.164759+0800 test1[8200:9002672] 異步2--操作1--<NSThread: 0x600002b42040>{number = 6, name = (null)}
2021-03-20 16:52:43.166518+0800 test1[8200:9002672] 異步2--操作2--<NSThread: 0x600002b42040>{number = 6, name = (null)}
2021-03-20 16:52:43.166932+0800 test1[8200:9002672] 異步3--操作1--<NSThread: 0x600002b42040>{number = 6, name = (null)}
2021-03-20 16:52:45.173185+0800 test1[8200:9002672] 異步3--操作2--<NSThread: 0x600002b42040>{number = 6, name = (null)}
image.png

3.2.4并行+異步

NSLog(@"主流恒start--%@", [NSThread currentThread]);
    dispatch_async(concurrent_queue, ^{
        NSLog(@"異步1--操作1--%@", [NSThread currentThread]);
        sleep(3);
        NSLog(@"異步1--操作2--%@", [NSThread currentThread]);
    });
    dispatch_async(concurrent_queue, ^{
        NSLog(@"異步2--操作1--%@", [NSThread currentThread]);
        sleep(1);
        NSLog(@"異步2--操作2--%@", [NSThread currentThread]);
    });
    dispatch_async(concurrent_queue, ^{
        NSLog(@"異步3--操作1--%@", [NSThread currentThread]);
        sleep(2);
        NSLog(@"異步3--操作2--%@", [NSThread currentThread]);
    });
    NSLog(@"主流程end-----%@", [NSThread currentThread]);
2021-03-20 16:44:46.396510+0800 test1[7871:8996717] 主流恒start--<NSThread: 0x600000b8dd80>{number = 1, name = main}
2021-03-20 16:44:46.396648+0800 test1[7871:8996717] 主流程end-----<NSThread: 0x600000b8dd80>{number = 1, name = main}
2021-03-20 16:44:46.396687+0800 test1[7871:8996802] 異步1--操作1--<NSThread: 0x600000be8080>{number = 3, name = (null)}
2021-03-20 16:44:46.396702+0800 test1[7871:8996806] 異步2--操作1--<NSThread: 0x600000b9c900>{number = 5, name = (null)}
2021-03-20 16:44:46.396707+0800 test1[7871:8996803] 異步3--操作1--<NSThread: 0x600000bb9f40>{number = 4, name = (null)}
2021-03-20 16:44:47.398008+0800 test1[7871:8996806] 異步2--操作2--<NSThread: 0x600000b9c900>{number = 5, name = (null)}
2021-03-20 16:44:48.397575+0800 test1[7871:8996803] 異步3--操作2--<NSThread: 0x600000bb9f40>{number = 4, name = (null)}
2021-03-20 16:44:49.398078+0800 test1[7871:8996802] 異步1--操作2--<NSThread: 0x600000be8080>{number = 3, name = (null)}
image.png

結(jié)論

1.對(duì)于同步執(zhí)行的任務(wù)帆吻,不管是放在并行隊(duì)列還是串行隊(duì)列中域那,都是按順序執(zhí)行,且當(dāng)上一個(gè)任務(wù)完成以后才執(zhí)行下一個(gè)任務(wù)猜煮。
2.異步執(zhí)行的任務(wù)次员,串行隊(duì)列會(huì)開(kāi)啟一個(gè)新線(xiàn)程,串行執(zhí)行任務(wù)王带,并行隊(duì)列會(huì)開(kāi)啟多個(gè)新線(xiàn)程淑蔚,并行執(zhí)行任務(wù)。

image.png

3.3死鎖

//  串行隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("cooci", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1");
    // 異步函數(shù)
    dispatch_async(queue, ^{
        NSLog(@"2");
        dispatch_sync(queue, ^{
            NSLog(@"3");
        });
        NSLog(@"4");
    });
    NSLog(@"5");
image.png

結(jié)果:輸出1愕撰、5刹衫、2以后產(chǎn)生死鎖崩潰
造成死鎖的原因:輸出2以后醋寝,將輸出3的這個(gè)同步函數(shù)(紅框部分)添加到同步隊(duì)列,那么如果要執(zhí)行紅框部分的代碼带迟,按照隊(duì)列先進(jìn)先出的規(guī)則音羞,則需要先執(zhí)行完排在前面的異步函數(shù)(綠框部分),但是該異步函數(shù)又需等待紅框部分執(zhí)行完以后仓犬,產(chǎn)生死鎖嗅绰。
結(jié)論:在串行隊(duì)列中添加同步任務(wù)時(shí),注意線(xiàn)程阻塞的問(wèn)題搀继,iOS主隊(duì)列是串行隊(duì)列窘面,如果在主線(xiàn)程執(zhí)行過(guò)程中向主隊(duì)列中添加同步操作時(shí)也會(huì)產(chǎn)生死鎖,另外開(kāi)辟一個(gè)線(xiàn)程向主隊(duì)列添加同步操作則不會(huì)產(chǎn)生死鎖叽躯。

例如在viewDidLoad函數(shù)中調(diào)用serialQueueProblem會(huì)在輸出1以后產(chǎn)生死鎖崩潰财边。

- (void)serialQueueProblem{
    NSLog(@"1");
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"2");
    });
    NSLog(@"3");
}

如果調(diào)用方式換成這樣則正常輸出123

[NSThread detachNewThreadSelector:@selector(serialQueueProblem) toTarget:self withObject:nil];

3.4其他用法

3.4.1 dispatch_once

- (void)dispatchOnce{
    static dispatch_once_t onceToken;
    NSLog(@"%ld", onceToken);
    dispatch_once(&onceToken, ^{
//        只會(huì)執(zhí)行一次
        NSLog(@"1%@", [NSThread currentThread]);
    });
}

調(diào)用三次的執(zhí)行結(jié)果

2021-03-21 18:17:02.376201+0800 test1[67067:9754075] 0
2021-03-21 18:17:02.376363+0800 test1[67067:9754075] 1<NSThread: 0x600002d85e40>{number = 1, name = main}
2021-03-21 18:17:02.376480+0800 test1[67067:9754075] -1
2021-03-21 18:17:02.376559+0800 test1[67067:9754075] -1

常用于實(shí)現(xiàn)一個(gè)單例

+ (instancetype)sharedInstance {
    static XXObject *_instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[XXObject alloc] init];
    });
    return _instance;
}

3.4.2 dispatch_after

多長(zhǎng)時(shí)間之后將任務(wù)添加到隊(duì)列中,所以任務(wù)并不是精準(zhǔn)的三秒之后再執(zhí)行
第一個(gè)參數(shù):dispatch_time_t類(lèi)型险毁,用于指定延遲時(shí)間
第二個(gè)參數(shù):指定要追加處理的隊(duì)列
第三個(gè)參數(shù):指定要執(zhí)行的任務(wù)Block

- (void)dispatchAfter{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"1%@", [NSThread currentThread]);
    });
    NSLog(@"2%@", [NSThread currentThread]);
}
2021-03-21 18:21:35.749123+0800 test1[67266:9757808] 2<NSThread: 0x60000057d0c0>{number = 1, name = main}
2021-03-21 18:21:39.037124+0800 test1[67266:9757808] 1<NSThread: 0x60000057d0c0>{number = 1, name = main}

3.4.3 Dispatch Source

Dispatch Source的種類(lèi):
1制圈、DISPATCH_SOURCE_TYPE_DATA_ADD 變量增加
2、DISPATCH_SOURCE_TYPE_DATA_OR 變量 OR
3畔况、DISPATCH_SOURCE_TYPE_MACH_SEND MACH端口發(fā)送
4鲸鹦、DISPATCH_SOURCE_TYPE_MACH_RECV MACH端口接收
5、DISPATCH_SOURCE_TYPE_MEMORYPRESSURE 內(nèi)存壓力 (注:iOS8后可用)
6跷跪、DISPATCH_SOURCE_TYPE_PROC 檢測(cè)到與進(jìn)程相關(guān)的事件
7馋嗜、DISPATCH_SOURCE_TYPE_READ 可讀取文件映像
8、DISPATCH_SOURCE_TYPE_SIGNAL 接收信號(hào)
9吵瞻、DISPATCH_SOURCE_TYPE_TIMER 定時(shí)器
10葛菇、DISPATCH_SOURCE_TYPE_VNODE 文件系統(tǒng)有變更
11、DISPATCH_SOURCE_TYPE_WRITE 可寫(xiě)入文件映像

使用DISPATCH_SOURCE_TYPE_TIMER可以實(shí)現(xiàn)一個(gè)每三秒執(zhí)行一次的定時(shí)器

- (void)dispatchSource{
    _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC, 0);
    dispatch_source_set_event_handler(_timer, ^{
        NSLog(@"1%@", [NSThread currentThread]);
    });
    NSLog(@"2%@", [NSThread currentThread]);
    dispatch_resume(_timer);
    NSLog(@"3%@", [NSThread currentThread]);
}
2021-03-21 18:39:52.466493+0800 test1[68104:9773071] 2<NSThread: 0x600000c492c0>{number = 1, name = main}
2021-03-21 18:39:52.466664+0800 test1[68104:9773071] 3<NSThread: 0x600000c492c0>{number = 1, name = main}
2021-03-21 18:39:52.476591+0800 test1[68104:9773071] 1<NSThread: 0x600000c492c0>{number = 1, name = main}
2021-03-21 18:39:55.467553+0800 test1[68104:9773071] 1<NSThread: 0x600000c492c0>{number = 1, name = main}
2021-03-21 18:39:58.467371+0800 test1[68104:9773071] 1<NSThread: 0x600000c492c0>{number = 1, name = main}
2021-03-21 18:40:01.467143+0800 test1[68104:9773071] 1<NSThread: 0x600000c492c0>{number = 1, name = main}

3.4.4 dispatch_apply

按指定的次數(shù)將指定的Block追加到指定的Dispatch Queue中橡羞,并等待全部處理執(zhí)行結(jié)束眯停,用在并行隊(duì)列執(zhí)行順序無(wú)序,用在串行隊(duì)列則按順序執(zhí)行

- (void)dispatchApply{
    dispatch_queue_t queue1 = dispatch_queue_create("aaa", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue2 = dispatch_queue_create("aaa", DISPATCH_QUEUE_SERIAL);
    dispatch_apply(5, queue1, ^(size_t index) {
        NSLog(@"并行隊(duì)列%ld%@", index, [NSThread mainThread]);
    });
    NSLog(@"并行結(jié)束-----");
    dispatch_apply(5, queue2, ^(size_t index) {
        NSLog(@"串行隊(duì)列%ld%@", index, [NSThread mainThread]);
    });
    NSLog(@"串行結(jié)束-----");
}
2021-03-21 18:55:42.463961+0800 test1[68871:9787727] 并行隊(duì)列3<NSThread: 0x600002c34380>{number = 1, name = (null)}
2021-03-21 18:55:42.463966+0800 test1[68871:9787725] 并行隊(duì)列1<NSThread: 0x600002c34380>{number = 1, name = (null)}
2021-03-21 18:55:42.463966+0800 test1[68871:9787728] 并行隊(duì)列2<NSThread: 0x600002c34380>{number = 1, name = (null)}
2021-03-21 18:55:42.464026+0800 test1[68871:9787730] 并行隊(duì)列4<NSThread: 0x600002c34380>{number = 1, name = (null)}
2021-03-21 18:55:42.463961+0800 test1[68871:9787529] 并行隊(duì)列0<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.464151+0800 test1[68871:9787529] 并行結(jié)束-----
2021-03-21 18:55:42.464242+0800 test1[68871:9787529] 串行隊(duì)列0<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.464341+0800 test1[68871:9787529] 串行隊(duì)列1<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.464434+0800 test1[68871:9787529] 串行隊(duì)列2<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.464674+0800 test1[68871:9787529] 串行隊(duì)列3<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.464891+0800 test1[68871:9787529] 串行隊(duì)列4<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.465079+0800 test1[68871:9787529] 串行結(jié)束-----

3.4.5 dispatch_barrier

  • 柵欄函數(shù)之前的任務(wù)執(zhí)行完以后卿泽,并且柵欄函數(shù)執(zhí)行完莺债,才執(zhí)行后面的操作
  • 串行隊(duì)列或者系統(tǒng)提供的全局并發(fā)隊(duì)列,這個(gè)柵欄函數(shù)的作用等同于一個(gè)同步函數(shù)的作用
  • dispatch_barrier_sync和dispatch_barrier_async的區(qū)別是,在當(dāng)前線(xiàn)程中的操作签夭,是否需要等待自己執(zhí)行完再執(zhí)行
- (void)dispatchBarrier{
    dispatch_queue_t queue = dispatch_queue_create("bbb", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"1%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        sleep(1);
        NSLog(@"2%@", [NSThread currentThread]);
    });
    dispatch_barrier_sync(queue, ^{
        sleep(1);
        NSLog(@"barrier%@", [NSThread currentThread]);
    });
    NSLog(@"barrier done");
    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"3%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        sleep(1);
        NSLog(@"4%@", [NSThread currentThread]);
    });
}
2021-03-21 19:11:09.974409+0800 test1[69598:9801166] 2<NSThread: 0x600000850640>{number = 6, name = (null)}
2021-03-21 19:11:10.974576+0800 test1[69598:9801168] 1<NSThread: 0x600000850600>{number = 4, name = (null)}
2021-03-21 19:11:11.975488+0800 test1[69598:9801093] barrier<NSThread: 0x6000008220c0>{number = 1, name = main}
2021-03-21 19:11:11.975850+0800 test1[69598:9801093] barrier done
2021-03-21 19:11:12.980667+0800 test1[69598:9801166] 4<NSThread: 0x600000850640>{number = 6, name = (null)}
2021-03-21 19:11:13.977532+0800 test1[69598:9801168] 3<NSThread: 0x600000850600>{number = 4, name = (null)}

如果把dispatch_barrier_sync換成dispatch_barrier_async

2021-03-21 19:12:25.502966+0800 test1[69660:9802632] barrier done
2021-03-21 19:12:26.503388+0800 test1[69660:9802717] 2<NSThread: 0x600001504280>{number = 6, name = (null)}
2021-03-21 19:12:27.507601+0800 test1[69660:9802728] 1<NSThread: 0x6000015823c0>{number = 3, name = (null)}
2021-03-21 19:12:28.511868+0800 test1[69660:9802728] barrier<NSThread: 0x6000015823c0>{number = 3, name = (null)}
2021-03-21 19:12:29.514776+0800 test1[69660:9802718] 4<NSThread: 0x600001581bc0>{number = 4, name = (null)}
2021-03-21 19:12:30.515791+0800 test1[69660:9802728] 3<NSThread: 0x6000015823c0>{number = 3, name = (null)}

3.5 diapatch_group

將要并發(fā)執(zhí)行的多個(gè)任務(wù)合并為一組齐邦,這樣調(diào)用者就可以知道這些任務(wù)何時(shí)能全部執(zhí)行完

3.5.1 新建group

dispatch_group_t group = dispatch_group_create();

3.5.2 將任務(wù)添加到group

用法一:dispatch_group_async

- (void)dispatchGroup1{
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("aaa", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_async(group, queue, ^{
        sleep(2);
        NSLog(@"1%@", [NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        sleep(1);
        NSLog(@"2%@", [NSThread currentThread]);
    });
    dispatch_group_notify(group, queue, ^{
        NSLog(@"notify%@", [NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        sleep(1);
        NSLog(@"3%@", [NSThread currentThread]);
    });
}
2021-03-21 20:28:06.280832+0800 test1[72687:9846592] 2<NSThread: 0x600001854a00>{number = 4, name = (null)}
2021-03-21 20:28:06.280833+0800 test1[72687:9846593] 3<NSThread: 0x60000183a7c0>{number = 3, name = (null)}
2021-03-21 20:28:07.279869+0800 test1[72687:9846591] 1<NSThread: 0x60000184e300>{number = 7, name = (null)}
2021-03-21 20:28:07.280195+0800 test1[72687:9846591] notify<NSThread: 0x60000184e300>{number = 7, name = (null)}

用法二:dispatch_group_enter+dispatch_group_leave配對(duì)使用

- (void)dispatchGroup2{
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("111", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        sleep(2);
        NSLog(@"1%@", [NSThread currentThread]);
        dispatch_group_leave(group);
    });
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        sleep(1);
        NSLog(@"2%@", [NSThread currentThread]);
        dispatch_group_leave(group);
    });
    dispatch_group_notify(group, queue, ^{
        NSLog(@"notify%@", [NSThread currentThread]);
    });
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        sleep(1);
        NSLog(@"3%@", [NSThread currentThread]);
        dispatch_group_leave(group);
    });
}
2021-03-21 20:44:53.567884+0800 test1[73477:9862570] 2<NSThread: 0x6000024a04c0>{number = 5, name = (null)}
2021-03-21 20:44:53.567930+0800 test1[73477:9862573] 3<NSThread: 0x6000024946c0>{number = 3, name = (null)}
2021-03-21 20:44:54.567761+0800 test1[73477:9862572] 1<NSThread: 0x6000024bf380>{number = 6, name = (null)}
2021-03-21 20:44:54.568120+0800 test1[73477:9862572] notify<NSThread: 0x6000024bf380>{number = 6, name = (null)}

3.5.3 監(jiān)聽(tīng)group里面的任務(wù)是否都完成

方法一:dispatch_group_notify使用方法如3.5.2
方法二:dispatch_group_wait設(shè)置等待時(shí)間,在等待時(shí)間結(jié)束后第租,如果還沒(méi)有執(zhí)行完任務(wù)組措拇,則返回。返回0代表執(zhí)行成功慎宾,非0則執(zhí)行失敗

- (void)dispatchGroupWait{
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("aaa", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_async(group, queue, ^{
        sleep(2);
        NSLog(@"1%@", [NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        sleep(1);
        NSLog(@"2%@", [NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        sleep(1);
        NSLog(@"3%@", [NSThread currentThread]);
    });
    long ret = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)));
    NSLog(@"ret = %ld", ret);
}
2021-03-21 20:57:35.552239+0800 test1[74073:9874594] 2<NSThread: 0x60000376c500>{number = 5, name = (null)}
2021-03-21 20:57:35.552252+0800 test1[74073:9874597] 3<NSThread: 0x60000376e540>{number = 3, name = (null)}
2021-03-21 20:57:36.552133+0800 test1[74073:9874595] 1<NSThread: 0x600003738780>{number = 4, name = (null)}
2021-03-21 20:57:36.552526+0800 test1[74073:9874485] ret = 0

如果把dispatch_group_wait的等待時(shí)長(zhǎng)減少到1秒則返回非0

3.6 信號(hào)量 dispatch_semaphore

  • dispatch_semaphore_create(long value);創(chuàng)建信號(hào)量丐吓,參數(shù)為設(shè)置信號(hào)量的初始值
  • dispatch_semaphore_signal(dispatch_semaphore_t dsema);發(fā)送信號(hào)量浅悉,信號(hào)量的值+1
  • dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);等待信號(hào)量,第一個(gè)為當(dāng)前等待的信號(hào)量汰蜘,第二個(gè)參數(shù)為超時(shí)時(shí)間仇冯。在信號(hào)量≤0的時(shí)候會(huì)一直等待,直到超時(shí)族操,并且會(huì)阻塞該線(xiàn)程苛坚,當(dāng)信號(hào)量>0時(shí)會(huì)繼續(xù)執(zhí)行,信號(hào)量-1色难。

使用信號(hào)量控制最大并發(fā)數(shù)

- (void)dispatchSemaphore{
    dispatch_group_t group = dispatch_group_create();
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
    dispatch_queue_t queue = dispatch_queue_create("qqq", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 10; i ++) {
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_group_async(group, queue, ^{
            sleep(1);
            NSLog(@"%d%@", i, [NSThread currentThread]);
            dispatch_semaphore_signal(semaphore);
        });
    }
    dispatch_group_notify(group, queue, ^{
        NSLog(@"done");
    });
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末泼舱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子枷莉,更是在濱河造成了極大的恐慌娇昙,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件笤妙,死亡現(xiàn)場(chǎng)離奇詭異冒掌,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蹲盘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)股毫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人召衔,你說(shuō)我怎么就攤上這事铃诬。” “怎么了苍凛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵趣席,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我醇蝴,道長(zhǎng)宣肚,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任悠栓,我火速辦了婚禮钉寝,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘闸迷。我一直安慰自己,他們只是感情好俘枫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布腥沽。 她就那樣靜靜地躺著,像睡著了一般鸠蚪。 火紅的嫁衣襯著肌膚如雪今阳。 梳的紋絲不亂的頭發(fā)上师溅,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音盾舌,去河邊找鬼墓臭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛妖谴,可吹牛的內(nèi)容都是我干的窿锉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼膝舅,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼嗡载!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起仍稀,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤洼滚,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后技潘,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體遥巴,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年享幽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了铲掐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡琉闪,死狀恐怖迹炼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情颠毙,我是刑警寧澤斯入,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站蛀蜜,受9級(jí)特大地震影響刻两,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜滴某,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一磅摹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧霎奢,春花似錦户誓、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至晤硕,卻和暖如春悼潭,著一層夾襖步出監(jiān)牢的瞬間庇忌,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工舰褪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留皆疹,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓占拍,卻偏偏與公主長(zhǎng)得像略就,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子刷喜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1.基本介紹 什么是GCD Grand Central Dispatch (GCD) 是異步執(zhí)行任務(wù)的技術(shù)之一残制。開(kāi)...
    淺笑11閱讀 297評(píng)論 0 1
  • 1.GCD簡(jiǎn)介 Grand Central Dispatch(GCD)是 Apple 開(kāi)發(fā)的一個(gè)多核編程的較新的解...
    冰鎮(zhèn)西瓜_5089閱讀 435評(píng)論 0 1
  • 系列文章: 多線(xiàn)程 多線(xiàn)程 pthread、NSThread 多線(xiàn)程 GCD 多線(xiàn)程 NSOperation 多線(xiàn)...
    林安530閱讀 358評(píng)論 0 0
  • 多線(xiàn)程開(kāi)發(fā)是日常開(kāi)發(fā)任務(wù)中不可缺少的一部分掖疮,在iOS開(kāi)發(fā)中常用到的多線(xiàn)程開(kāi)發(fā)技術(shù)有GCD初茶、NSOperation、...
    風(fēng)緊扯呼閱讀 813評(píng)論 0 1
  • 一浊闪、什么是GCD 全稱(chēng)是Grand Central Dispatch恼布,可譯為“牛逼的中樞調(diào)度器”,純C語(yǔ)言搁宾,提供了...
    懂得_sniper閱讀 1,869評(píng)論 0 0