GCD小結(轉載)

0. Brief Introduction

     GCD,全稱Grand Central Dispath,是蘋果開發的一種支持並行操作的機制。它的主要部件是一個FIFO隊列和一個線程池,前者用來添加任務,後者用來執行任務。

     GCD中的FIFO隊列稱爲dispatch queue,它可以保證先進來的任務先得到執行(但不保證一定先執行結束)。

     通過與線程池的配合,dispatch queue分爲下面兩種:

  •      Serial Dispatch Queue -- 線程池只提供一個線程用來執行任務,所以後一個任務必須等到前一個任務執行結束才能開始。
  •      Concurrent Dispatch Queue -- 線程池提供多個線程來執行任務,所以可以按序啓動多個任務併發執行。

1. Basic Management

     我們可以通過dispatch_queue_cretae來創建隊列,然後用dispatch_release釋放。比如下面兩段代碼分別創建串行隊列和並行隊列:

  1. dispatch_queue_t serialQ = dispatch_queue_create("eg.gcd.SerialQueue", DISPATCH_QUEUE_SERIAL);  
  2. dispatch_async(serialQ, ^{  
  3.     // Code here  
  4. });  
  5. dispatch_release(serialQ);  
  6.   
  7. dispatch_queue_t concurrentQ = dispatch_queue_create("eg.gcd.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);  
  8. dispatch_async(concurrentQ, ^{  
  9.     // Code here  
  10. });  
  11. dispatch_release(concurrentQ);  

     而系統默認就有一個串行隊列main_queue和並行隊列global_queue:

  1. dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
  2. dispatch_queue_t mainQ = dispatch_get_main_queue();  

     通常,我們可以在global_queue中做一些long-running的任務,完成後在main_queue中更新UI,避免UI阻塞,無法響應用戶操作:

  1. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
  2.     // long-running task  
  3.     dispatch_async(dispatch_get_main_queue(), ^{  
  4.         // update UI  
  5.     });  
  6. });  

     上面提到dispatch_async這個接口,用來提交blcok給指定queue進行異步執行。這個接口會在成功提交block後立即返回,然後繼續執行下去。由於block是定義在棧上的,所以需要將其複製到堆上,見這裏

     與之相對應的是dispatch_sync接口,提交block以供同步執行。這個接口會等到block執行結束才返回,所以不需要複製block。So,如果在調用該接口在當前queue上指派任務,就會導致deadlock。維基百科上給了段示例代碼:

  1. dispatch_queue_t exampleQueue = dispatch_queue_create("com.example.unique.identifier", NULL );  
  2. dispatch_sync( exampleQueue,^{  
  3.   dispatch_sync( exampleQueue,^{  
  4.     printf("I am now deadlocked...\n");  
  5.   });});  
  6. dispatch_release( exampleQueue );  
     如果追求的是併發,那麼dispatch_sync有什麼用呢?關於dispatch_sync的用途,SO上有討論

     

2. Normal Control

  • dispatch_once

     如果沒有記錯的話,在iOS Con 2012上,大衆點評的同學分享了個Topic叫《iOS開發最佳實踐》,開篇講singleton實現的演進(怎麼演進都有可以挑的刺),後面轉折說要把精力放到用戶看得到的地方。

     如果把singleton和best practice放在一起,那麼我很容易聯想到dispatch_once這個函數,它可以保證整個應用程序生命週期中某段代碼只被執行一次

  1. static dispatch_once_t onceToken;  
  2. dispatch_once(&onceToken, ^{  
  3.     // code to be executed once  
  4. });  

  • dispatch_after

     有時候我們需要等個幾秒鐘然後做個動畫或者給個提示,這時候可以用dispatch_after這個函數:

  1. double delayInSeconds = 2.0;  
  2. dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);  
  3. dispatch_after(popTime, dispatch_get_main_queue(), ^(void){  
  4.     // code to be executed on the main queue after delay  
  5. });  

  • dispatch_set_target_queue

     通過dispatch_set_target_queue函數可以設置一個dispatch queue的優先級,或者指定一個dispatch source相應的事件處理提交到哪個queue上。

  1. dispatch_set_target_queue(serialQ, globalQ);  

  • dispatch_apply

     執行某個代碼片段若干次。

  1. dispatch_apply(10, globalQ, ^(size_t index) {  
  2.     // do sth. 10 times  
  3. });  

  • dispatch group

     Dispatch Group機制允許我們監聽一組任務是否完成:

  1. dispatch_group_t group = dispatch_group_create();  
  2. dispatch_group_async(group, concurrentQ, blk0);  
  3. dispatch_group_async(group, concurrentQ, blk1);  
  4. dispatch_group_async(group, concurrentQ, blk2);  
  5. dispatch_group_notify(group, mainQ, ^{  
  6.     // update UI  
  7. });  
  8. dispatch_release(group);  

     或者說同步地等待一段時間看是否結束:

  1. dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);  
  2. dispatch_group_wait(group, time);  

  • dispatch_barrier_async

     通過dispatch_barrier_async函數提交的任務會等它前面的任務執行結束纔開始,然後它後面的任務必須等它執行完畢才能開始。

  1. dispatch_async(concurrentQ, blk0);  
  2. dispatch_async(concurrentQ, blk1);  
  3. dispatch_barrier_async(concurrentQ, blk_barrier);  
  4. dispatch_async(concurrentQ, blk2);  

這份官方文檔很清晰地按功能爲GCD相關函數進行了分類。

Jason Lee @ Hangzhou

原文鏈接:http://blog.csdn.net/jasonblog/article/details/7816999

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章