關於GCD多工處理

溫特兒發表於2019-03-16

假如你說:像這樣的 GCD 多工應用的場景不太算多, 我說:但這不是你沒必要知道怎麼去處理使用GCD處理多工的事情的理由

其實在 iOS 開發中,像這樣的多工處理,很簡單,因為 Apple 已經幫你封裝好了各種好用的 API,比如 GCD,現在我就說下具體的用法,所有的註釋都在程式碼裡,寫的應該說是很詳細了。

dispatch_group:建立任務組,然後非同步執行加入到 group 的每個任務,比如向 group 新增了3個任務,那麼這3個任務,會同時執行的,由於每個任務執行時間(耗時)不一樣,所有在所有的任務都執行結束後,會呼叫 dispatch_group_notify,可以在這裡處理多個任務的結果。

dispatch_group_t group = dispatch_group_create(); // 建立任務組 dispatch_group_enter(group):// 建立任務,新增至 group dispatch_group_leave(group):// 任務結束,離開 group

// eg:
dispatch_group_enter(group);
// 建立任務(程式碼)
...
dispatch_group_leave(group);
複製程式碼

需要提醒的一點:使用dispatch_group建立的多工,enter 和 leave 必須成對出現,否則,就呵呵了~

- (void)testGroupMultitask
{
    NSLog(@"testGroupMultitask===============");
    // 1.建立任務組
    dispatch_group_t group = dispatch_group_create();
    // 2.加入第一個任務
    dispatch_group_enter(group);
    
    NSMutableString *groupResult = [NSMutableString string];
    
    // 模擬一個6秒的請求
    [self fakeRequestWithDelay:6 result:^(NSString *string, NSError *error) {
        /*
         在這裡我們設定的dispatch_group_wait時間是5秒,但是我們這個任務的回撥時間是6秒。所以結果是5秒過後wait超時,程式繼續往下執行,列印-> "wait時間已經到了"。
         然而這個任務還線上程裡執行,一直到執行dispatch_group_leave這個任務才完成。
         */
        NSString *result = [NSString stringWithFormat:@"任務組1完成 %@",string];
        [groupResult appendString:result];
        [groupResult appendString:@"\n"];
        NSLog(@"------%@",string);
        dispatch_group_leave(group);
    }];
    
    // 3.加入第二個任務
    dispatch_group_enter(group);
    
    /*
     這裡我發現一個問題,我設定的dispatch_after的延時時間是3秒,也就是3秒後把block中的任務加入執行緒;
     所以結果應該是在dispatch_group_wait時間內就能完成的,列印順序應該是在 "wait時間已經到了" 之前才對, 但是列印的順序卻是先列印:"wait時間已經到了",然後列印:任務組2完成;
     我猜測這個延時執行的程式碼,是非同步的等待,並不是阻塞執行緒的,
     */
    dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, 3*NSEC_PER_SEC);
    dispatch_after(tt, dispatch_get_main_queue(), ^{
        NSString *result = @"任務組2完成 delay 3 seconds";
        [groupResult appendString:result];
        [groupResult appendString:@"\n"];
        NSLog(@"------%@",result);
        dispatch_group_leave(group);
    });
    
    // 4.加入第三個任務
    dispatch_group_enter(group);
    NSString *result = @"任務組3完成";
    [groupResult appendString:result];
    [groupResult appendString:@"\n"];
    NSLog(@"------%@",result);
    dispatch_group_leave(group);
    
    // 5.執行到這句程式碼後會等待5秒,等待關聯的任務組group裡的所有任務完成。如果在5秒內都完成了,返回0並繼續執行;如果超時未完成,返回非0並繼續執行。所以任務組裡的任務無論是否全部完成,都會繼續執行。
    int waitTime = 5;
    dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(waitTime*NSEC_PER_SEC)));
    NSLog(@"wait時間已經到了 %i seconds",waitTime);
    
    // 6.notify會簡體關聯的任務組group中的所有任務是否都已完成(dispatch_group_enter和dispatch_group_leave匹配),完成了就會執行block
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"------所有任務組都完成了 \n %@",groupResult);
    });
}
複製程式碼

執行以上程式碼,在控制檯輸出結果:

2016-07-10 17:53:10.397 | testGroupMultitask===============
2016-07-10 17:53:10.397 | ------任務組3完成
2016-07-10 17:53:15.399 | wait時間已經到了 5 seconds
2016-07-10 17:53:15.403 | ------任務組2完成 delay 3 seconds
2016-07-10 17:53:16.986 | ------delay 6 seconds
2016-07-10 17:53:16.987 | 
------所有任務組都完成了
任務組3完成
任務組2完成 delay 3 seconds
任務組1完成 delay 6 seconds
複製程式碼

對照列印的結果,可以看出,上面group各任務的執行順序。

最後再說下,enter和leave,不成對的後果:就是這個缺少leave的任務,在開闢的子執行緒裡一直在等待結束,所以 dispatch_group_notify 一直收不到所有任務完成的通知

相關文章