多個網絡請求同時執行,等所有網絡請求完成,再統一做其他操作,我們可能會想到dispatch_group_async、dispatch_group_notify結合使用。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue, ^{ NSLog(@"任務一完成"); }); dispatch_group_async(group, queue, ^{ NSLog(@"任務二完成"); }); dispatch_group_async(group, queue, ^{ NSLog(@"任務三完成"); }); //在分組的所有任務完成后觸發 dispatch_group_notify(group, queue, ^{ NSLog(@"所有任務完成"); });
或者使用柵欄
- (void)barrier { // dispatch_queue_t queue = dispatch_queue_create("com.lai.www", DISPATCH_QUEUE_CONCURRENT); dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0); dispatch_async(queue, ^{ NSLog(@"任務1-1完成"); }); dispatch_async(queue, ^{ NSLog(@"任務1-2完成"); }); dispatch_async(queue, ^{ NSLog(@"任務1-3完成"); }); dispatch_barrier_async(queue, ^{ NSLog(@"以上任務都完成 dispatch_barrie完成"); }); }
比如上述寫法,內部執行的是同步操作沒有問題,如果以上三個任務都是異步的,比如是網絡請求,那么就達不到我們想要的效果。因為異步,請求沒有回來,dispatch_group_notify或者dispatch_barrier_async已經執行了。
我們可以采用信號量
或者dispatch_group_enter、dispatch_group_leave
實現。
核心思想:將異步變成同步
下述描述了常見場景下的代碼實現:包括順序執行和同時執行異步操作
順序執行 :
方式 : 信號量semaphore (必須放在子線程 dispatch_semaphore_wait會卡死主線程) (例:1執行完了執行2)
- (void)serialBySemaphore { dispatch_async(dispatch_get_global_queue(0, 0), ^{ dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); [self requestOneWithSuccessBlock:^{ dispatch_semaphore_signal(semaphore); }]; dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); [self requestTwoWithBlock:^{ }]; }); }
執行到dispatch_semaphore_wait時,由於信號量為0,進行等待,請求1完成后調用dispatch_semaphore_signal ,信號量不再為0,接着執行請求2
方式: GCD dispatch_group_enter/leave (例: 1, 2 同時執行 執行完了再執行3)
-(void)serialByGroupWait { dispatch_group_t group = dispatch_group_create(); dispatch_group_enter(group); [self requestOneWithSuccessBlock:^{ dispatch_group_leave(group); }]; dispatch_group_enter(group); [self requestTwoWithBlock:^{ dispatch_group_leave(group); }]; // 1 2同時執行 dispatch_group_wait(group, DISPATCH_TIME_FOREVER);// 1 2 執行完 下面才會執行 dispatch_group_enter(group); [self requestThreeWithBlock:^{ dispatch_group_leave(group); }]; // 1 2 3 都完成 才會執行 dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{ NSLog(@"all request done!"); }); }
執行到dispatch_group_wait時,由於enter數不等於leave數,進行等待,請求1,2都完成后調用dispatch_group_leave ,enter數等於leave數,接着執行請求3。 請求1,2,3都執行后,dispatch_group_notify執行
方式三:回調中執行
- (void) serialByCallBack { [self requestOneWithSuccessBlock:^{ [self requestTwoWithBlock:^{ }]; }]; }
low方法,請求一多,嵌套惡心
同時執行 :
方式:信號量
-(void)concurrentBySemaphore { dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_semaphore_t sema = dispatch_semaphore_create(0); [self requestOneWithSuccessBlock:^{ dispatch_semaphore_signal(sema); }]; dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); }); dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_semaphore_t sema = dispatch_semaphore_create(0); [self requestTwoWithSuccessBlock:^{ dispatch_semaphore_signal(sema); }]; dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"全部搞完了"); }); }
方式:dispatch_group_enter
-(void)concurrentByGroup { dispatch_group_t group = dispatch_group_create(); dispatch_group_enter(group); [self requestOneWithSuccessBlock:^{ dispatch_group_leave(group); }]; dispatch_group_enter(group); [self requestTwoWithBlock:^{ dispatch_group_leave(group); }]; // 1 2 都完成 才會執行 dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{ NSLog(@"all request done!"); }); }
擴充:循環請求情況 順序請求/同時請求
*模擬循環網絡請求 同時進行 統一回調 (GCD + 信號量方式)
- (void)concurrentTest1 { dispatch_group_t group = dispatch_group_create(); for (int i = 0 ; i < 5; i++) { dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_semaphore_t sema = dispatch_semaphore_create(0); // 模擬請求 ↓ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(3); NSLog(@"任務%d完成",i); dispatch_semaphore_signal(sema); }); // 模擬請求 上 dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); }); } dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"全部搞完了"); }); }
執行結果:
00:21:38.413337+0800 mmmm[4595:182516] 任務1完成 00:21:38.413337+0800 mmmm[4595:182518] 任務3完成 00:21:38.413358+0800 mmmm[4595:182517] 任務2完成 00:21:38.413358+0800 mmmm[4595:182515] 任務0完成 00:21:38.413447+0800 mmmm[4595:182519] 任務4完成 00:21:38.413843+0800 mmmm[4595:182428] 全部搞完了
*模擬循環網絡請求 同時進行 統一回調 (GCD + group enter/leave 方式)
- (void)concurrentTest2 { dispatch_group_t group = dispatch_group_create(); for (int i = 0 ; i < 5; i++) { dispatch_group_enter(group); // 模擬請求 ↓ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(3); NSLog(@"任務%d完成",i); dispatch_group_leave(group); }); // 模擬請求 ↑ } dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"全部搞完了"); }); }
執行結果:
2019-04-12 00:26:38.607040+0800 mmmm[4641:184613] 任務0完成 2019-04-12 00:26:38.607043+0800 mmmm[4641:184612] 任務2完成 2019-04-12 00:26:38.607059+0800 mmmm[4641:184611] 任務3完成 2019-04-12 00:26:38.607067+0800 mmmm[4641:184610] 任務1完成 2019-04-12 00:26:38.607088+0800 mmmm[4641:184625] 任務4完成 2019-04-12 00:26:38.607353+0800 mmmm[4641:184559] 全部搞完了
*模擬循環網絡請求 順序進行 (GCD + 信號量方式)
- (void)serialTest1 { dispatch_semaphore_t sema = dispatch_semaphore_create(0); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ for (int i = 0 ; i < 5; i++) { NSLog(@"開始%d",i); // 模擬請求 ↓ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(3); NSLog(@"任務%d完成",i); dispatch_semaphore_signal(sema); }); // 模擬請求 上 dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); } NSLog(@"全部搞完了"); }); }
執行結果
2019-04-12 01:31:45.291818+0800 mmmm[5417:215007] 開始0 2019-04-12 01:31:48.297299+0800 mmmm[5417:215008] 任務0完成 2019-04-12 01:31:48.297746+0800 mmmm[5417:215007] 開始1 2019-04-12 01:31:51.298592+0800 mmmm[5417:215008] 任務1完成 2019-04-12 01:31:51.298841+0800 mmmm[5417:215007] 開始2 2019-04-12 01:31:54.300477+0800 mmmm[5417:215008] 任務2完成 2019-04-12 01:31:54.300908+0800 mmmm[5417:215007] 開始3 2019-04-12 01:31:57.305197+0800 mmmm[5417:215008] 任務3完成 2019-04-12 01:31:57.305623+0800 mmmm[5417:215007] 開始4 2019-04-12 01:32:00.311062+0800 mmmm[5417:215008] 任務4完成 2019-04-12 01:32:00.311407+0800 mmmm[5417:215007] 全部搞完了
*模擬循環網絡請求 順序進行 (GCD + group enter/leave 方式)
- (void)serialTest2 { dispatch_group_t group = dispatch_group_create(); for (int i = 0 ; i < 5; i++) { dispatch_group_enter(group); // 模擬請求 ↓ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ sleep(6 - i); NSLog(@"任務%d完成",i); dispatch_group_leave(group); }); // 模擬請求 ↑ dispatch_group_wait(group, DISPATCH_TIME_FOREVER); // 順序執行與同步執行的不同點 } dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"全部搞完了"); }); }
執行結果
2019-04-12 00:33:46.020376+0800 mmmm[4748:188409] 任務0完成 2019-04-12 00:33:51.021098+0800 mmmm[4748:188409] 任務1完成 2019-04-12 00:33:55.022758+0800 mmmm[4748:188409] 任務2完成 2019-04-12 00:33:58.023783+0800 mmmm[4748:188409] 任務3完成 2019-04-12 00:34:00.027929+0800 mmmm[4748:188409] 任務4完成 2019-04-12 00:34:00.028444+0800 mmmm[4748:188374] 全部搞完了