iOS線程之GCD初探

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

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

什么是GCD?

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

methodList info


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

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

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

//獲取代碼現在運行的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中并且執行。
void dispatch_sync( dispatch_queue_t queue, dispatch_block_t block);

 //block 在指定時間在queue中執行
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 是否執行過
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
 
//在分組group中的queue隊列執行block
void dispatch_group_async( dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);

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

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

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

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

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

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

實戰演練全局隊列

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

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

自定義隊列

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個異步線程,要求前兩個個執行完再去執行后面的三個的時候例子:
     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任務進行完成的時候,最后在執行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] =================**
一個組內的所有任務都進行完了才會執行task的函數。


# 分組多任務等待 ABCDEF ,ABCD執行5秒,5秒之后就執行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");
    });
輸出:
# 代碼執行到wait的時候會等待5秒之后再執行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] =================**

同時處理多數據不管順序

          dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    
          /*! dispatch_apply函數說明
           10      *
           11      *  @brief  dispatch_apply函數是dispatch_sync函數和Dispatch Group的關聯API
           12      *         該函數按指定的次數將指定的Block追加到指定的Dispatch Queue中,并等到全部的處理執行結束
           13      *
           14      *  @param 10    指定重復次數  指定10次
           15      *  @param queue 追加對象的Dispatch Queue
           16      *  @param index 帶有參數的Block, index的作用是為了按執行的順序區分各個Block
           17      *
           18      */
          dispatch_apply(10, queue, ^(size_t index) {
                  NSLog(@"%d", index);
              
              });
          NSLog(@"done");
輸出:
# 這個和上邊講的分組類似,多事務處理,處理結束后再執行代碼。
# 這個是同步的,代碼按順序執行,分組的是異步執行的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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,071評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,409評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,569評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,360評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,895評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,123評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,643評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,559評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,742評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,981評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,363評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,622評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,354評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,707評論 2 370

推薦閱讀更多精彩內容