1.GCD的概念
GCD為Grand Central Dispatch的縮寫。
它主要用于優(yōu)化應用程序以支持多核處理器以及其他對稱多處理系統。它是一個在線程池模式的基礎上執(zhí)行的并行任務。在Mac OS X 10.6雪豹中首次推出,也可在IOS 4及以上版本使用。
2.GCD的隊列和任務
GCD包括兩個核心概念:隊列和任務
2.1隊列
隊列是一種特殊的線性表,遵循FIFO(先進先出)原則,新添加的任務在隊尾,執(zhí)行任務的時候從隊首開始讀取并執(zhí)行。隊列分為串行隊列和并行隊列,區(qū)別主要是:隊列中任務執(zhí)行的順序不同,開啟的線程數也不同。
串行隊列
每個時間段只有一個任務在執(zhí)行,只開啟一個線程,一個任務執(zhí)行完以后再執(zhí)行下一個任務。
并行隊列
可以有多個任務在并發(fā)執(zhí)行,可以開啟多個線程同時處理多個任務。
2.2任務
任務就是需要執(zhí)行的一組操作,在GCD是放在block中的那一段代碼,任務分為同步任務和異步任務,區(qū)別是:是否等待隊列的任務執(zhí)行結束,以及是否具備開啟新線程的能力。
同步sync
同步任務會等待操作執(zhí)行完畢,再執(zhí)行block外的操作,只能在當前線程中執(zhí)行任務。
異步async
異步任務不會等待操作執(zhí)行完畢,會直接繼續(xù)執(zhí)行block外的操作,可以在開啟新的線程執(zhí)行任務。
3.GCD的具體使用
3.1創(chuàng)建隊列
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隊列和任務的簡單組合
3.2.1串行+同步
// 串行隊列+同步
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并行+同步
// 并行隊列+同步
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串行+異步
// 串行隊列+異步
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)}

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)}

結論
1.對于同步執(zhí)行的任務,不管是放在并行隊列還是串行隊列中,都是按順序執(zhí)行,且當上一個任務完成以后才執(zhí)行下一個任務。
2.異步執(zhí)行的任務,串行隊列會開啟一個新線程,串行執(zhí)行任務,并行隊列會開啟多個新線程,并行執(zhí)行任務。
image.png
3.3死鎖
// 串行隊列
dispatch_queue_t queue = dispatch_queue_create("cooci", DISPATCH_QUEUE_SERIAL);
NSLog(@"1");
// 異步函數
dispatch_async(queue, ^{
NSLog(@"2");
dispatch_sync(queue, ^{
NSLog(@"3");
});
NSLog(@"4");
});
NSLog(@"5");

結果:輸出1、5、2以后產生死鎖崩潰
造成死鎖的原因:輸出2以后,將輸出3的這個同步函數(紅框部分)添加到同步隊列,那么如果要執(zhí)行紅框部分的代碼,按照隊列先進先出的規(guī)則,則需要先執(zhí)行完排在前面的異步函數(綠框部分),但是該異步函數又需等待紅框部分執(zhí)行完以后,產生死鎖。
結論:在串行隊列中添加同步任務時,注意線程阻塞的問題,iOS主隊列是串行隊列,如果在主線程執(zhí)行過程中向主隊列中添加同步操作時也會產生死鎖,另外開辟一個線程向主隊列添加同步操作則不會產生死鎖。
例如在viewDidLoad函數中調用serialQueueProblem會在輸出1以后產生死鎖崩潰。
- (void)serialQueueProblem{
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
}
如果調用方式換成這樣則正常輸出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, ^{
// 只會執(zhí)行一次
NSLog(@"1%@", [NSThread currentThread]);
});
}
調用三次的執(zhí)行結果
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
常用于實現一個單例
+ (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í)行
第一個參數:dispatch_time_t類型,用于指定延遲時間
第二個參數:指定要追加處理的隊列
第三個參數:指定要執(zhí)行的任務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的種類:
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 內存壓力 (注:iOS8后可用)
6、DISPATCH_SOURCE_TYPE_PROC 檢測到與進程相關的事件
7、DISPATCH_SOURCE_TYPE_READ 可讀取文件映像
8、DISPATCH_SOURCE_TYPE_SIGNAL 接收信號
9、DISPATCH_SOURCE_TYPE_TIMER 定時器
10、DISPATCH_SOURCE_TYPE_VNODE 文件系統有變更
11、DISPATCH_SOURCE_TYPE_WRITE 可寫入文件映像
使用DISPATCH_SOURCE_TYPE_TIMER可以實現一個每三秒執(zhí)行一次的定時器
- (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
按指定的次數將指定的Block追加到指定的Dispatch Queue中,并等待全部處理執(zhí)行結束,用在并行隊列執(zhí)行順序無序,用在串行隊列則按順序執(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(@"并行隊列%ld%@", index, [NSThread mainThread]);
});
NSLog(@"并行結束-----");
dispatch_apply(5, queue2, ^(size_t index) {
NSLog(@"串行隊列%ld%@", index, [NSThread mainThread]);
});
NSLog(@"串行結束-----");
}
2021-03-21 18:55:42.463961+0800 test1[68871:9787727] 并行隊列3<NSThread: 0x600002c34380>{number = 1, name = (null)}
2021-03-21 18:55:42.463966+0800 test1[68871:9787725] 并行隊列1<NSThread: 0x600002c34380>{number = 1, name = (null)}
2021-03-21 18:55:42.463966+0800 test1[68871:9787728] 并行隊列2<NSThread: 0x600002c34380>{number = 1, name = (null)}
2021-03-21 18:55:42.464026+0800 test1[68871:9787730] 并行隊列4<NSThread: 0x600002c34380>{number = 1, name = (null)}
2021-03-21 18:55:42.463961+0800 test1[68871:9787529] 并行隊列0<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.464151+0800 test1[68871:9787529] 并行結束-----
2021-03-21 18:55:42.464242+0800 test1[68871:9787529] 串行隊列0<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.464341+0800 test1[68871:9787529] 串行隊列1<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.464434+0800 test1[68871:9787529] 串行隊列2<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.464674+0800 test1[68871:9787529] 串行隊列3<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.464891+0800 test1[68871:9787529] 串行隊列4<NSThread: 0x600002c34380>{number = 1, name = main}
2021-03-21 18:55:42.465079+0800 test1[68871:9787529] 串行結束-----
3.4.5 dispatch_barrier
- 柵欄函數之前的任務執(zhí)行完以后,并且柵欄函數執(zhí)行完,才執(zhí)行后面的操作
- 串行隊列或者系統提供的全局并發(fā)隊列,這個柵欄函數的作用等同于一個同步函數的作用
- dispatch_barrier_sync和dispatch_barrier_async的區(qū)別是,在當前線程中的操作,是否需要等待自己執(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í)行的多個任務合并為一組,這樣調用者就可以知道這些任務何時能全部執(zhí)行完
3.5.1 新建group
dispatch_group_t group = dispatch_group_create();
3.5.2 將任務添加到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配對使用
- (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)聽group里面的任務是否都完成
方法一:dispatch_group_notify使用方法如3.5.2
方法二:dispatch_group_wait設置等待時間,在等待時間結束后,如果還沒有執(zhí)行完任務組,則返回。返回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的等待時長減少到1秒則返回非0
3.6 信號量 dispatch_semaphore
- dispatch_semaphore_create(long value);創(chuàng)建信號量,參數為設置信號量的初始值
- dispatch_semaphore_signal(dispatch_semaphore_t dsema);發(fā)送信號量,信號量的值+1
- dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);等待信號量,第一個為當前等待的信號量,第二個參數為超時時間。在信號量≤0的時候會一直等待,直到超時,并且會阻塞該線程,當信號量>0時會繼續(xù)執(zhí)行,信號量-1。
使用信號量控制最大并發(fā)數
- (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");
});
}
