iOS線程之GCD初探

簡述:
說道線程,離不開并行和串行,所謂并行,就是100賽跑,每個賽道就是一個線程,每個線程之間互不影響,同時都可以運行事件,就是10個賽道都可以有運動員跑步了,誰跑的慢或者跑的快,都不影響其他的人。串行就不一樣了,串行是1個賽道10個運動員再跑接力賽,第一個跑到終點第二個在接著跑,依次類推,前邊的不走,后邊的也走不了的,所以串行上面的事件是一個一個運行的,同時只能是一個人再跑。

在iOS或者OS里面,一般用GCD就能處理較多的事務,下面就談一下GCD的用法。

什么是GCD?

全稱是Grand Central Dispatch,可譯為“牛逼的中樞調度器”
純C語言,提供了非常多強大的函數(shù)

methodList info


//獲取主線程 就是更新UI的線程
dispatch_queue_t dispatch_get_main_queue(void);

 //獲取全局隊列
dispatch_queue_t dispatch_get_global_queue( long identifier, unsigned long flags);

//創(chuàng)建一個隊列 名字是label 屬性可以寫為NULL  
dispatch_queue_t dispatch_queue_create( const char *label dispatch_queue_attr_t attr);
dispatch_release(queue)//釋放隊列

//獲取代碼現(xiàn)在運行的queue
dispatch_queue_t dispatch_get_current_queue( void);

 //獲取隊列的名字
const char * dispatch_queue_get_label(dispatch_queue_t queue);

//異步把代碼塊block交給queue隊列中處理
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

// 同步將block加入到queue中并且執(zhí)行。
void dispatch_sync( dispatch_queue_t queue, dispatch_block_t block);

 //block 在指定時間在queue中執(zhí)行
void dispatch_after( dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);

 
//幾個調度事件同事加入到queue中去,最好是全局隊列才行。
void dispatch_apply( size_t iterations, dispatch_queue_t queue, void (^block)( size_t));

// block 是否執(zhí)行過
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
 
//在分組group中的queue隊列執(zhí)行block
void dispatch_group_async( dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);

//創(chuàng)建線程分組
dispatch_group_t dispatch_group_create( void);

 //分組的計數(shù)+1
void dispatch_group_enter( dispatch_group_t group);

//分組計數(shù) -1
void dispatch_group_leave( dispatch_group_t group);

// 當分組中的事務處理完了執(zhí)行block
void dispatch_group_notify( dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);

//等待timeout時間后執(zhí)行 group中的事務
long dispatch_group_wait( dispatch_group_t group, dispatch_time_t timeout);

 //并行狀態(tài)下 queue前面的并行事務處理完成了在執(zhí)行block,然后執(zhí)行下邊的并行代碼
//比如 ABCDEF D事務等到ABC都完成了在執(zhí)行EF事務的
void dispatch_barrier_async( dispatch_queue_t queue, dispatch_block_t block);

實戰(zhàn)演練全局隊列

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(queue, ^{
        //異步執(zhí)行
        dispatch_sync(dispatch_get_main_queue(), ^{
            //這里面更新UI
        });
    });
    dispatch_sync(queue, ^{
       //同步執(zhí)行
    });

自定義隊列

dispatch_queue_t queue = dispatch_queue_create("com.apple.fgyong", DISPATCH_QUEUE_SERIAL);
    //
//#define DISPATCH_QUEUE_SERIAL   同步隊列
//#define DISPATCH_QUEUE_CONCURRENT 異步隊列
    dispatch_async(queue, ^{
        NSLog(@"下載圖片1=====%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"下載圖片2=====%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"下載圖片3=====%@",[NSThread currentThread]);
    });
    NSLog(@"main:%@",[NSThread mainThread]);
當queue屬性為 DISPATCH_QUEUE_CONCURRENT輸出:
**2016-03-28 16:53:25.848 GCD_Demo[12338:347984] ****下載圖片****3=====<NSThread: 0x7fabda100250>{number = 4, name = (null)}**
**2016-03-28 16:53:25.848 GCD_Demo[12338:347982] ****下載圖片****2=====<NSThread: 0x7fabda2008a0>{number = 3, name = (null)}**
**2016-03-28 16:53:25.848 GCD_Demo[12338:347937] main:<NSThread: 0x7fabd8c04ee0>{number = 1, name = main}**
**2016-03-28 16:53:25.848 GCD_Demo[12338:347981] ****下載圖片****1=====<NSThread: 0x7fabd8c0a010>{number = 2, name = (null)}** 線程達到了4個
當queue屬性為DISPATCH_QUEUE_SERIAL輸出:
**2016-03-28 16:46:54.501 GCD_Demo[12272:344348] main:<NSThread: 0x7fd379704cf0>{number = 1, name = main}**
**2016-03-28 16:46:54.501 GCD_Demo[12272:344382] ****下載圖片****1=====<NSThread: 0x7fd37971bda0>{number = 2, name = (null)}**
**2016-03-28 16:46:54.502 GCD_Demo[12272:344382] ****下載圖片****2=====<NSThread: 0x7fd37971bda0>{number = 2, name = (null)}**
**2016-03-28 16:46:54.502 GCD_Demo[12272:344382] ****下載圖片****3=====<NSThread: 0x7fd37971bda0>{number = 2, name = (null)}**
線程只有2個

多個異步線程問題

# 當ABC 3個異步線程,要求前兩個個執(zhí)行完再去執(zhí)行后面的三個的時候例子:
     dispatch_queue_t queue = dispatch_queue_create("com.apple.fgyong", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue, ^{
        NSLog(@"queue1 begin");
        sleep(2);
        NSLog(@"queue1 end");
    });
    dispatch_async(queue, ^{
        NSLog(@"queue2 begin");
        sleep(2);
        NSLog(@"queue2 end");
    });
    dispatch_barrier_sync(queue, ^{
        NSLog(@"main:%@",[NSThread mainThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"queue3 begin");
        sleep(2);
        NSLog(@"queue3 end");
    });
輸出:

**2016-03-28 17:01:01.319 GCD_Demo[12463:353702] queue2 begin**
**2016-03-28 17:01:01.319 GCD_Demo[12463:353703] queue1 begin**
**2016-03-28 17:01:03.324 GCD_Demo[12463:353703] queue1 end**
**2016-03-28 17:01:03.324 GCD_Demo[12463:353702] queue2 end**
**2016-03-28 17:01:03.325 GCD_Demo[12463:353657] main:<NSThread: 0x7f97ea604bf0>{number = 1, name = main}**
**2016-03-28 17:01:03.325 GCD_Demo[12463:353702] queue3 begin**
**2016-03-28 17:01:05.330 GCD_Demo[12463:353702] queue3 end**

線程分組

# 當多個任務同時進行的時候,也可以用group,ABCD任務進行完成的時候,最后在執(zhí)行task。
 

  dispatch_queue_t queue = dispatch_queue_create("com.apple.fgyong", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"task1 begin");
        sleep(2);
        NSLog(@"task1 end");
    });
    
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"task2 begin");
        sleep(2);
        NSLog(@"task2 end");
    });
    dispatch_group_notify(group, queue, ^{
        NSLog(@"=================");
    });
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"task3 begin");
        sleep(2);
        NSLog(@"task3 end");
    });
    
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"task4 begin");
        sleep(2);
        NSLog(@"task4 end");
    });
輸出:
**2016-03-28 17:08:45.002 GCD_Demo[12557:357162] task1 begin**
**2016-03-28 17:08:45.002 GCD_Demo[12557:357164] task4 begin**
**2016-03-28 17:08:45.002 GCD_Demo[12557:357161] task2 begin**
**2016-03-28 17:08:45.002 GCD_Demo[12557:357163] task3 begin**
**2016-03-28 17:08:47.005 GCD_Demo[12557:357162] task1 end**
**2016-03-28 17:08:47.005 GCD_Demo[12557:357163] task3 end**
**2016-03-28 17:08:47.005 GCD_Demo[12557:357164] task4 end**
**2016-03-28 17:08:47.005 GCD_Demo[12557:357161] task2 end**
**2016-03-28 17:08:47.006 GCD_Demo[12557:357161] =================**
一個組內的所有任務都進行完了才會執(zhí)行task的函數(shù)。


# 分組多任務等待 ABCDEF ,ABCD執(zhí)行5秒,5秒之后就執(zhí)行EF任務,不管ABCD是否成功。

    dispatch_queue_t queue = dispatch_queue_create("com.apple.fgyong", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"task1 begin");
        sleep(2);
        NSLog(@"task1 end");
    });
    
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"task2 begin");
        sleep(2);
        NSLog(@"task2 end");
    });
    dispatch_group_notify(group, queue, ^{
        NSLog(@"=================");
    });
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"task3 begin");
        sleep(6);
        NSLog(@"task3 end");
    });
    dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5*NSEC_PER_SEC)));
    NSLog(@"all end");
    dispatch_group_async(group, queue, ^{
        
        NSLog(@"task4 begin");
        sleep(2);
        NSLog(@"task4 end");
    });
輸出:
# 代碼執(zhí)行到wait的時候會等待5秒之后再執(zhí)行wait下邊的代碼,和sleep有點相似。
**2016-03-28 17:26:31.335 GCD_Demo[12745:366983] task3 begin**
**2016-03-28 17:26:31.335 GCD_Demo[12745:366978] task1 begin**
**2016-03-28 17:26:31.335 GCD_Demo[12745:366979] task2 begin**
**2016-03-28 17:26:33.340 GCD_Demo[12745:366978] task1 end**
**2016-03-28 17:26:33.340 GCD_Demo[12745:366979] task2 end**
**2016-03-28 17:26:36.336 GCD_Demo[12745:366894] all end**
**2016-03-28 17:26:36.336 GCD_Demo[12745:366979] task4 begin**
**2016-03-28 17:26:37.340 GCD_Demo[12745:366983] task3 end**
**2016-03-28 17:26:38.342 GCD_Demo[12745:366979] task4 end**
**2016-03-28 17:26:38.342 GCD_Demo[12745:366983] =================**

同時處理多數(shù)據(jù)不管順序

          dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    
          /*! dispatch_apply函數(shù)說明
           10      *
           11      *  @brief  dispatch_apply函數(shù)是dispatch_sync函數(shù)和Dispatch Group的關聯(lián)API
           12      *         該函數(shù)按指定的次數(shù)將指定的Block追加到指定的Dispatch Queue中,并等到全部的處理執(zhí)行結束
           13      *
           14      *  @param 10    指定重復次數(shù)  指定10次
           15      *  @param queue 追加對象的Dispatch Queue
           16      *  @param index 帶有參數(shù)的Block, index的作用是為了按執(zhí)行的順序區(qū)分各個Block
           17      *
           18      */
          dispatch_apply(10, queue, ^(size_t index) {
                  NSLog(@"%d", index);
              
              });
          NSLog(@"done");
輸出:
# 這個和上邊講的分組類似,多事務處理,處理結束后再執(zhí)行代碼。
# 這個是同步的,代碼按順序執(zhí)行,分組的是異步執(zhí)行的block
**2016-03-28 17:36:35.698 GCD_Demo[12857:372458] 1**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372463] 5**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372429] 4**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372464] 6**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372465] 7**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372462] 2**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372457] 0**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372461] 3**
**2016-03-28 17:36:35.699 GCD_Demo[12857:372458] 8**
**2016-03-28 17:36:35.699 GCD_Demo[12857:372429] 9**
**2016-03-28 17:36:35.699 GCD_Demo[12857:372429] done**
    

參考文章:Grand Central Dispatch (GCD) Reference
GCD提供的接口蠻多的,適用場景還是要熟練掌握,才能運用自如。
更多文章:www.fgyong.cn

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 1. GCD簡介 什么是GCD呢?我們先來看看百度百科的解釋簡單了解下概念 引自百度百科:Grand Centra...
    千尋_544f閱讀 496評論 0 0
  • 本文首發(fā)于我的個人博客:「程序員充電站」[https://itcharge.cn]文章鏈接:「傳送門」[https...
    ITCharge閱讀 350,600評論 308 1,927
  • 1. GCD簡介 iOS開發(fā)中多線程的API主要有pthread,NSThread,NSOperation和GCD...
    安東_Ace閱讀 1,387評論 0 6
  • 多線程 在iOS開發(fā)中為提高程序的運行效率會將比較耗時的操作放在子線程中執(zhí)行,iOS系統(tǒng)進程默認啟動一個主線程,用...
    郭豪豪閱讀 2,719評論 0 4
  • 剛剛看完了衡水中學的一篇文章,感覺好多東西需要我們去學習。比如說在學生的時間安排上,在學生的作業(yè)布置上,在晚自習的...
    裝蝴蝶朱閱讀 376評論 0 0

友情鏈接更多精彩內容