1. 程式人生 > >iOS學習——並發編程GCD

iOS學習——並發編程GCD

更新ui 情況 round 暫時 順序 eat 書寫 繼續 進行

 在iOS中使用的多線程技術有四種,Pthread、NSThread、GCD、NSOperation,但GCD與OP嚴格來說,應該叫並發編程技術。GCD雖然是用C語言書寫,但是蘋果對它做了很多封裝,讓它使用起來及其簡單方便,因此在OC開發中應用很廣。而OP則是在iOS4.0之後對GCD進行了一次封裝,增加了許多用GCD實現比較麻煩的功能,如最大並發數,線程暫停,取消以及依賴添加。

  GCD的使用其實可以拆分成兩步,一是隊列,二是任務/指令;隊列分為串行隊列、並發隊列、全局隊列以及主隊列,其中主隊列只在主線程上運行,但都遵守FIFO。任務則有異步任務與同步任務。

demo1 :

異步調用會訪問線程池調取線程,不開啟自線程的情況就是主隊列執行異步

//主隊列  異步任務
- (void)demo1 {
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    
    dispatch_async(mainQueue, ^{
        NSLog(@"%s %@",__FUNCTION__,[NSThread currentThread]);
    });
    
    NSLog(@"結束");
/*
 2017-11-16 19:23:41.644179+0800 iOS學習——GCD[8388:387757] 結束
 2017-11-16 19:23:41.645610+0800 iOS學習——GCD[8388:387757] -[ViewController demo1]_block_invoke <NSThread: 0x604000071200>{number = 1, name = main}
 
*/ }

demo2:

同步調用任務立刻執行

//主隊列  同步任務(如果主線程同步,主線程正在執行demo2這個任務,同步任務又要求主線程執行block內任務,由於線程只有執行完一個任務才能進行下一個,這樣資源爭奪就會死鎖,如果是放在子線程則沒有問題)
- (void)demo2 {
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    
    [NSThread detachNewThreadWithBlock:^{
        NSLog(@"%s",__FUNCTION__ );
        dispatch_sync(mainQueue, 
^{ NSLog(@"%s %@",__FUNCTION__,[NSThread currentThread]); }); NSLog(@"子線程走完 "); }]; NSLog(@"結束"); /* 2017-11-17 09:50:48.452495+0800 iOS學習——GCD[9829:634367] 結束 2017-11-17 09:50:48.452541+0800 iOS學習——GCD[9829:635350] -[ViewController demo2]_block_invoke 2017-11-17 09:50:48.453392+0800 iOS學習——GCD[9829:634367] -[ViewController demo2]_block_invoke_2 <NSThread: 0x60400007eac0>{number = 1, name = main} 2017-11-17 09:50:48.453540+0800 iOS學習——GCD[9829:635350] 子線程走完 */ }

demo3:

串行隊列同步任務阻塞主線程,由於隊列FIFO,所以保持順序

//串行隊列  同步任務 (gcd已經加入arc)
- (void)demo3 {
    dispatch_queue_t serialQueue = dispatch_queue_create("iosSerial", NULL);
    
    for (NSInteger i = 0; i < 10; i ++) {
        dispatch_sync(serialQueue, ^{
            NSLog(@"第%ld次,%s %@ ",i,__FUNCTION__,[NSThread currentThread]);
        });
    }
    NSLog(@"結束");
    /*
     2017-11-17 09:52:58.616681+0800 iOS學習——GCD[9854:637007] 第0次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.616871+0800 iOS學習——GCD[9854:637007] 第1次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.618652+0800 iOS學習——GCD[9854:637007] 第2次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.618805+0800 iOS學習——GCD[9854:637007] 第3次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.618944+0800 iOS學習——GCD[9854:637007] 第4次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.619485+0800 iOS學習——GCD[9854:637007] 第5次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.619606+0800 iOS學習——GCD[9854:637007] 第6次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.619715+0800 iOS學習——GCD[9854:637007] 第7次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.702830+0800 iOS學習——GCD[9854:637007] 第8次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.702967+0800 iOS學習——GCD[9854:637007] 第9次,-[ViewController demo3]_block_invoke <NSThread: 0x604000072280>{number = 1, name = main}
     2017-11-17 09:52:58.703120+0800 iOS學習——GCD[9854:637007] 結束
     */
}

demo4:

異步會調用線程池線程,不會阻塞主線程,只有執行完一個任務才能調用,由於串行隊列FIFO,所以順序執行

//串行隊列  異步任務
- (void)demo4 {
    dispatch_queue_t serialQueue = dispatch_queue_create("iosSerial", NULL);
    
    for (NSInteger i = 0; i < 10; i ++) {
        dispatch_async(serialQueue, ^{
            NSLog(@"第%ld次,%s %@ ",i,__FUNCTION__,[NSThread currentThread]);
        });
    }
    NSLog(@"結束");
    /*
     2017-11-17 09:56:50.914235+0800 iOS學習——GCD[9874:639468] 第0次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.914099+0800 iOS學習——GCD[9874:639183] 結束
     2017-11-17 09:56:50.916152+0800 iOS學習——GCD[9874:639468] 第1次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.917729+0800 iOS學習——GCD[9874:639468] 第2次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.918009+0800 iOS學習——GCD[9874:639468] 第3次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.918256+0800 iOS學習——GCD[9874:639468] 第4次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.918381+0800 iOS學習——GCD[9874:639468] 第5次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.918494+0800 iOS學習——GCD[9874:639468] 第6次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.918600+0800 iOS學習——GCD[9874:639468] 第7次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.951677+0800 iOS學習——GCD[9874:639468] 第8次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     2017-11-17 09:56:50.951871+0800 iOS學習——GCD[9874:639468] 第9次,-[ViewController demo4]_block_invoke <NSThread: 0x60400026d200>{number = 3, name = (null)}
     */
}

demo5:

並發隊列,依舊保持隊列FIFO特性,但是可以在一個任務未執行完取下一個任務執行,但是由於同步任務阻塞主線程,只有主線程調用任務,所以每次只從隊列中取一個任務

//並發隊列  同步任務
- (void)demo5 {
    dispatch_queue_t conQueue = dispatch_queue_create("iosConcurrent", DISPATCH_QUEUE_CONCURRENT);
    
    for (NSInteger i = 0; i < 10; i ++) {
        dispatch_sync(conQueue, ^{
            NSLog(@"第%ld次,%s %@ ",i,__FUNCTION__,[NSThread currentThread]);
        });
    }
    NSLog(@"結束");
    /*
     2017-11-17 10:01:15.328701+0800 iOS學習——GCD[9920:645669] 第0次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.328898+0800 iOS學習——GCD[9920:645669] 第1次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.328987+0800 iOS學習——GCD[9920:645669] 第2次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.329083+0800 iOS學習——GCD[9920:645669] 第3次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.329206+0800 iOS學習——GCD[9920:645669] 第4次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.329473+0800 iOS學習——GCD[9920:645669] 第5次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.329584+0800 iOS學習——GCD[9920:645669] 第6次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.329786+0800 iOS學習——GCD[9920:645669] 第7次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.329917+0800 iOS學習——GCD[9920:645669] 第8次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.330044+0800 iOS學習——GCD[9920:645669] 第9次,-[ViewController demo5]_block_invoke <NSThread: 0x600000070e80>{number = 1, name = main}
     2017-11-17 10:01:15.330191+0800 iOS學習——GCD[9920:645669] 結束

     */
}

demo6:

從運行的次數可以看出,並發隊列 異步調用的時候,每開啟一個線程,都能從隊列中取一個任務執行,所以沒辦法保證執行順序,而根據線程的number可以判斷出,線程從線程池中被拿出來執行完任務後,會回到線程池,等待再次被調用,如果任務未執行完,最先執行完的線程又回到線程池,則將會在此執行。

//並發隊列  異步任務
- (void)demo6 {
    dispatch_queue_t conQueue = dispatch_queue_create("iosConcurrent", DISPATCH_QUEUE_CONCURRENT);
    
    for (NSInteger i = 0; i < 10; i ++) {
        dispatch_async(conQueue, ^{
            if (i % 2 == 0) {
                [NSThread sleepForTimeInterval:1.f];//由於執行太快,特阻塞一秒
            }
            NSLog(@"第%ld次,%s %@ ",i,__FUNCTION__,[NSThread currentThread]);
        });
    }
    NSLog(@"結束");
    /*
     2017-11-17 10:10:02.883676+0800 iOS學習——GCD[9990:654627] 結束
     2017-11-17 10:10:02.883749+0800 iOS學習——GCD[9990:654784] 第1次,-[ViewController demo6]_block_invoke <NSThread: 0x60000027f8c0>{number = 3, name = (null)}
     2017-11-17 10:10:02.883773+0800 iOS學習——GCD[9990:654786] 第3次,-[ViewController demo6]_block_invoke <NSThread: 0x60000027f900>{number = 4, name = (null)}
     2017-11-17 10:10:02.884475+0800 iOS學習——GCD[9990:655044] 第5次,-[ViewController demo6]_block_invoke <NSThread: 0x60400046efc0>{number = 5, name = (null)}
     2017-11-17 10:10:02.884740+0800 iOS學習——GCD[9990:655045] 第7次,-[ViewController demo6]_block_invoke <NSThread: 0x60000027fcc0>{number = 6, name = (null)}
     2017-11-17 10:10:02.884875+0800 iOS學習——GCD[9990:655044] 第9次,-[ViewController demo6]_block_invoke <NSThread: 0x60400046efc0>{number = 5, name = (null)}
     2017-11-17 10:10:03.887784+0800 iOS學習——GCD[9990:654783] 第2次,-[ViewController demo6]_block_invoke <NSThread: 0x60000027fac0>{number = 7, name = (null)}
     2017-11-17 10:10:03.887784+0800 iOS學習——GCD[9990:654784] 第6次,-[ViewController demo6]_block_invoke <NSThread: 0x60000027f8c0>{number = 3, name = (null)}
     2017-11-17 10:10:03.887784+0800 iOS學習——GCD[9990:654786] 第8次,-[ViewController demo6]_block_invoke <NSThread: 0x60000027f900>{number = 4, name = (null)}
     2017-11-17 10:10:03.887788+0800 iOS學習——GCD[9990:654785] 第0次,-[ViewController demo6]_block_invoke <NSThread: 0x60400027fc80>{number = 8, name = (null)}
     2017-11-17 10:10:03.887834+0800 iOS學習——GCD[9990:655043] 第4次,-[ViewController demo6]_block_invoke <NSThread: 0x60000027f980>{number = 9, name = (null)}
     */
}

demo7、8:

與並發區別在與:1.並發可以命名 2.全局隊列在MRC下不需要釋放,而並發在MRC下需要主動釋放

//全局隊列  同步任務
- (void)demo7 {
    
    //第一個參數代表優先級,
   
    /* iOS8.0後
    *  - QOS_CLASS_USER_INTERACTIVE
    *  - QOS_CLASS_USER_INITIATED
    *  - QOS_CLASS_DEFAULT
    *  - QOS_CLASS_UTILITY
     *  - QOS_CLASS_BACKGROUND
    */
    /*
     ios 7.0 與8.0比對
     *  - DISPATCH_QUEUE_PRIORITY_HIGH:         QOS_CLASS_USER_INITIATED  高優先級
     *  - DISPATCH_QUEUE_PRIORITY_DEFAULT:      QOS_CLASS_DEFAULT  默認
     *  - DISPATCH_QUEUE_PRIORITY_LOW:          QOS_CLASS_UTILITY   低優先級
     *  - DISPATCH_QUEUE_PRIORITY_BACKGROUND:   QOS_CLASS_BACKGROUND 後臺執行,會很慢,需謹慎使用
     */
    
    /*
     第二個參數是占位參數,暫時沒有任何意義,為蘋果後續拓展使用
     */
    dispatch_queue_t conQueue = dispatch_get_global_queue(0, 0);
    
    for (NSInteger i = 0; i < 10; i ++) {
        dispatch_sync(conQueue, ^{
            NSLog(@"第%ld次,%s %@ ",i,__FUNCTION__,[NSThread currentThread]);
        });
    }
    NSLog(@"結束");

}

//全局隊列  異步任務
- (void)demo8 {

    dispatch_queue_t conQueue = dispatch_get_global_queue(0, 0);
    
    for (NSInteger i = 0; i < 10; i ++) {
        dispatch_async(conQueue, ^{
            NSLog(@"第%ld次,%s %@ ",i,__FUNCTION__,[NSThread currentThread]);
        });
    }
    NSLog(@"結束");
}

demo9:

同步線程設置依賴關系

//登錄   評論  關註 三個操作(登錄後才可以評論和關註)  評論或關註後要更新UI
//設置依賴
- (void)demo9 {
    dispatch_queue_t queue = dispatch_queue_create("ios", DISPATCH_QUEUE_CONCURRENT);

    dispatch_sync(queue, ^{
        NSLog(@"登錄 %@ ",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"評論 %@ ",[NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"關註 %@ ",[NSThread currentThread]);
    });
    
    /*
     2017-11-17 11:33:48.563496+0800 iOS學習——GCD[10351:720878] 登錄 <NSThread: 0x600000263f80>{number = 1, name = main}
     2017-11-17 11:33:48.563946+0800 iOS學習——GCD[10351:721028] 關註 <NSThread: 0x604000474380>{number = 3, name = (null)}
     2017-11-17 11:33:48.563946+0800 iOS學習——GCD[10351:721030] 評論 <NSThread: 0x604000474080>{number = 5, name = (null)}
     2017-11-17 11:33:48.739571+0800 iOS學習——GCD[10351:720878] 登錄 <NSThread: 0x600000263f80>{number = 1, name = main}
     2017-11-17 11:33:48.740086+0800 iOS學習——GCD[10351:721030] 評論 <NSThread: 0x604000474080>{number = 5, name = (null)}
     2017-11-17 11:33:48.740100+0800 iOS學習——GCD[10351:721146] 關註 <NSThread: 0x600000473040>{number = 4, name = (null)}
     */
}

demo10:

由結果可以看出,dispatch_barrier_async可以設置依賴關系,只有之前的代碼執行完畢,才執行dispatch_barrier_async內代碼,所有代碼都是開啟子線程執行,不阻塞當前線程;但是它會設置當前內容為同步執行,只有執行dispatch_barrier_async內任務,才能繼續執行。如果需要並發執行復數任務作為依賴,然後並發執行復數任務,沒有合適dispatch_barrier_async執行條件,這樣就必須開啟一個空dispatch_barrier_async才行

- (void)demo10 {
    dispatch_queue_t queue = dispatch_queue_create("ios", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        NSLog(@"登錄 %@ ",[NSThread currentThread]);
        sleep(1);
    });
    dispatch_barrier_async(queue, ^{
        sleep(5);
        NSLog(@"評論 %@ ",[NSThread currentThread]);
    });
    
    dispatch_async(queue, ^{
        sleep(1);
        NSLog(@"關註 %@ ",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"收藏 %@ ",[NSThread currentThread]);
    });
    NSLog(@"結束主線程任務  ");
    /*
     2017-11-17 11:40:15.901540+0800 iOS學習——GCD[10445:729689] 結束主線程任務
     2017-11-17 11:40:15.901692+0800 iOS學習——GCD[10445:729786] 登錄 <NSThread: 0x604000471800>{number = 3, name = (null)}
     2017-11-17 11:40:21.910464+0800 iOS學習——GCD[10445:729786] 評論 <NSThread: 0x604000471800>{number = 3, name = (null)}
     2017-11-17 11:40:21.910723+0800 iOS學習——GCD[10445:729798] 收藏 <NSThread: 0x60000026ea00>{number = 4, name = (null)}
     2017-11-17 11:40:22.913477+0800 iOS學習——GCD[10445:729786] 關註 <NSThread: 0x604000471800>{number = 3, name = (null)}
     */
}

demo11:

當group內任務全部執行完畢,就會調用notify通知,所有任務都是異步執行

#pragma mark 調度組

- (void)demo11 {
    dispatch_group_t groupQueue = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("ios", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_async(groupQueue, queue, ^{
        sleep(8);
            NSLog(@"登錄 %@ ",[NSThread currentThread]);
    });
    dispatch_group_async(groupQueue, queue, ^{
        NSLog(@"評論 %@ ",[NSThread currentThread]);
    });
    dispatch_group_async(groupQueue, queue, ^{
      
            NSLog(@"關註 %@ ",[NSThread currentThread]);
            
    });
    dispatch_notify(groupQueue, dispatch_get_main_queue(), ^{//通知完成,使用主隊列,讓任務在主線程執行
        NSLog(@"更新UI %@ ",[NSThread currentThread]);

    });
    NSLog(@"結束主線程任務  ");
    
    /*
     2017-11-17 11:51:20.427599+0800 iOS學習——GCD[10489:740925] 結束主線程任務
     2017-11-17 11:51:20.427726+0800 iOS學習——GCD[10489:741115] 關註 <NSThread: 0x6040004765c0>{number = 4, name = (null)}
     2017-11-17 11:51:20.427726+0800 iOS學習——GCD[10489:741147] 評論 <NSThread: 0x604000475f80>{number = 3, name = (null)}
     2017-11-17 11:51:28.429514+0800 iOS學習——GCD[10489:741114] 登錄 <NSThread: 0x604000475f80>{number = 5, name = (null)}
     2017-11-17 11:51:28.429725+0800 iOS學習——GCD[10489:740925] 更新UI <NSThread: 0x60000007f7c0>{number = 1, name = main}
     */
}

demo12、13:

dispatch_group_wait可以阻塞當前線程是假,等待調度組完成,第二個參數為阻塞時間,如果時間大於調度組完成時間,那麽調度組完成後,阻塞取消;如果小於調度組完成時間,那麽到設定的阻塞時間後,也不再阻塞當前線程,DISPATCH_TIME_FOREVER參數則保證阻塞當前線程直到調度組完成

- (void)demo12 {
    dispatch_group_t groupQueue = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("ios", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_async(groupQueue, queue, ^{
        sleep(8);
        NSLog(@"登錄 %@ ",[NSThread currentThread]);
    });
    dispatch_group_async(groupQueue, queue, ^{
        NSLog(@"評論 %@ ",[NSThread currentThread]);
    });
    dispatch_group_async(groupQueue, queue, ^{
        
        NSLog(@"關註 %@ ",[NSThread currentThread]);
        
    });
    //第一個參數: 時間起點
    //第二個參數: 時間長度
    dispatch_group_wait(groupQueue, dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC));
    
    dispatch_notify(groupQueue, dispatch_get_main_queue(), ^{//通知完成,使用主隊列,讓任務在主線程執行
        NSLog(@"更新UI %@ ",[NSThread currentThread]);
        
    });
    NSLog(@"結束主線程任務  ");
    /*
     2017-11-17 11:53:24.627643+0800 iOS學習——GCD[10507:743414] 評論 <NSThread: 0x60000026ac40>{number = 3, name = (null)}
     2017-11-17 11:53:24.627643+0800 iOS學習——GCD[10507:743373] 關註 <NSThread: 0x60000026ac80>{number = 4, name = (null)}
     2017-11-17 11:53:32.631477+0800 iOS學習——GCD[10507:743374] 登錄 <NSThread: 0x604000463300>{number = 5, name = (null)}
     2017-11-17 11:53:32.631708+0800 iOS學習——GCD[10507:743191] 結束主線程任務
     2017-11-17 11:53:32.632605+0800 iOS學習——GCD[10507:743191] 更新UI <NSThread: 0x60400006fb00>{number = 1, name = main}
     */
}
- (void)demo13 {
    dispatch_group_t groupQueue = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("ios", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_async(groupQueue, queue, ^{
        sleep(8);
        NSLog(@"登錄 %@ ",[NSThread currentThread]);
    });
    dispatch_group_async(groupQueue, queue, ^{
        NSLog(@"評論 %@ ",[NSThread currentThread]);
    });
    dispatch_group_async(groupQueue, queue, ^{
        
        NSLog(@"關註 %@ ",[NSThread currentThread]);
        
    });
    

    dispatch_group_wait(groupQueue,  dispatch_time(DISPATCH_TIME_NOW, 4 * NSEC_PER_SEC));
    
    dispatch_notify(groupQueue, dispatch_get_main_queue(), ^{//通知完成,使用主隊列,讓任務在主線程執行
        NSLog(@"更新UI %@ ",[NSThread currentThread]);
        
    });
    NSLog(@"結束主線程任務  ");
/*
 2017-11-17 13:52:26.915659+0800 iOS學習——GCD[10810:807557] 評論 <NSThread: 0x604000275640>{number = 3, name = (null)}
 2017-11-17 13:52:26.915659+0800 iOS學習——GCD[10810:807556] 關註 <NSThread: 0x604000275400>{number = 4, name = (null)}
 2017-11-17 13:52:30.916019+0800 iOS學習——GCD[10810:807242] 結束主線程任務
 2017-11-17 13:52:34.919903+0800 iOS學習——GCD[10810:807559] 登錄 <NSThread: 0x604000275640>{number = 5, name = (null)}
 2017-11-17 13:52:34.920194+0800 iOS學習——GCD[10810:807242] 更新UI <NSThread: 0x600000065f00>{number = 1, name = main}

 */
    
}

demo14:

dispatch_group_enter,dispatch_group_leave在項目中必須成對出現,不然會崩潰。如果dispatch_group_async內執行異步線程,notify是無法識別到異步線程是否完成,只會認為執行完dispatch_group_async內任務就通知;但是當用上enter和leave後,只要把enter放在調度組任務創建前,然後leave放在你認為會結束的地方,那麽只有等leave執行,notify才會執行

- (void)demo14 {
    dispatch_group_t groupQueue = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("ios", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_group_async(groupQueue, queue, ^{

        dispatch_async(queue, ^{
            sleep(8);
            NSLog(@"登錄 %@ ",[NSThread currentThread]);
        });
    });

    
    dispatch_group_enter(groupQueue);
    dispatch_group_async(groupQueue, queue, ^{
        dispatch_async(queue, ^{
            sleep(4);
            NSLog(@"評論 %@ ",[NSThread currentThread]);
            dispatch_group_leave(groupQueue);

        });
   
    });
    
    dispatch_group_enter(groupQueue);
    dispatch_group_async(groupQueue, queue, ^{
        
        NSLog(@"關註 %@ ",[NSThread currentThread]);
        
    });
    dispatch_group_leave(groupQueue);

    
    dispatch_notify(groupQueue, dispatch_get_main_queue(), ^{//通知完成,使用主隊列,讓任務在主線程執行
        NSLog(@"更新UI %@ ",[NSThread currentThread]);
        
    });
    NSLog(@"結束主線程任務  ");
    /*
     2017-11-17 14:05:44.459763+0800 iOS學習——GCD[10883:822533] 結束主線程任務
     2017-11-17 14:05:44.459822+0800 iOS學習——GCD[10883:822914] 關註 <NSThread: 0x60000027f000>{number = 3, name = (null)}
     2017-11-17 14:05:48.462705+0800 iOS學習——GCD[10883:822911] 評論 <NSThread: 0x6040002772c0>{number = 4, name = (null)}
     2017-11-17 14:05:48.462927+0800 iOS學習——GCD[10883:822533] 更新UI <NSThread: 0x604000071640>{number = 1, name = main}
     2017-11-17 14:05:52.460289+0800 iOS學習——GCD[10883:822938] 登錄 <NSThread: 0x604000273100>{number = 5, name = (null)}
     */
}

iOS學習——並發編程GCD