GCD的第一次接觸
- 上一篇文章,從這里開始學習GCD。
-
為了方便地使用GCD,蘋果提供了一些方法方便我們將block放在主線程 或 后臺線程執行,或者延后執行。
// 后臺執行: dispatch_async(dispatch_get_global_queue(0, 0), ^{ // something }); // 主線程執行: dispatch_async(dispatch_get_main_queue(), ^{ // something }); // 一次性執行: static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // code to be executed once }); // 延遲2秒執行: double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds *NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ // code to be executed on the main queue after delay });
-
GCD中有三種隊列類型:
-
The main queue:
與主線程功能相同。實際上,提交至main queue的任務會在主線程中執行。main queue可以調用dispatch_get_main_queue()來獲得。因為main queue是與主線程相關的,所以這是一個串行隊列。
-
Global queues:
全局隊列是并發隊列,并由整個進程共享。進程中存在三個全局隊列:高、中(默認)、低三個優先級隊列。可以調用dispatch_get_global_queue函數傳入優先級來訪問隊列。
-
用戶隊列:
用戶隊列 (GCD并不這樣稱呼這種隊列, 但是沒有一個特定的名字來形容這種隊列,所以我們稱其為用戶隊列) 是用函數 dispatch_queue_create 創建的隊列. 這些隊列是串行的。正因為如此,它們可以用來完成同步機制, 有點像傳統線程中的mutex。
-
-
dispatch_async:
將任務進行異步并行處理,不一定需要一個任務處理完后才能處理下一個。
-
dispatch queue分為下面兩種:
而系統默認就有一個串行隊列main_queue和并行隊列global_queue:
Serial Dispatch Queue -- 線程池只提供一個線程用來執行任務,所以后一個任務必須等到前一個任務執行結束才能開始。 Concurrent Dispatch Queue -- 線程池提供多個線程來執行任務,所以可以按序啟動多個任務并發執行。
而系統默認就有一個串行隊列main_queue和并行隊列global_queue:
-
dispatch_get_main_queue() 函數:
就是返回主線程,^{} 封裝的就是任務代碼,這樣嵌套方式就可以從一個隊列queue,跳到另一個queue
-
dispatch_get_global_queue(dispatch_queue_priority_t priority,
unsigned long flags):會獲取一個全局隊列
,我們姑且理解為系統為我們開啟的一些全局線程。dispatch_queue_priority_t priority: 隊列中近程的優先級。
unsigned long flags:
flag
作為保留字段備用(一般為0)
-
dispatch_group_async的使用
dispatch_group_async可以實現監聽一組任務是否完成,完成后得到通知執行其他的操作。這個方法很有用,比如你執行三個下載任務,當三個任務都下載完成后你才通知界面說完成的了。下面是一段例子代碼:
- (IBAction)touchUpInsideByThreadOne:(id)sender { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:6]; NSLog(@"group1 [NSThread sleepForTimeInterval:6];"); }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:3]; NSLog(@"group2 [NSThread sleepForTimeInterval:3];"); }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"group3 [NSThread sleepForTimeInterval:1];"); }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"main thread."); }); dispatch_release(group); }
-
dispatch_barrier_async的使用
dispatch_barrier_async是在前面的任務執行結束后它才執行,而且它后面的任務等它執行完成之后才會執行
- (IBAction)touchUpInsideByThreadOne:(id)sender { dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:3]; NSLog(@"dispatch_async1"); }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"dispatch_async2"); }); dispatch_barrier_async(queue, ^{ NSLog(@"dispatch_barrier_async"); [NSThread sleepForTimeInterval:0.5]; }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"dispatch_async3"); }); }
執行結果為:
2013-07-24 17:01:54.580 NSThreadAndBlockDemo[2153:12b03] dispatch_async2 2013-07-24 17:01:56.580 NSThreadAndBlockDemo[2153:12303] dispatch_async1 2013-07-24 17:01:56.580 NSThreadAndBlockDemo[2153:12303] dispatch_barrier_async 2013-07-24 17:01:58.083 NSThreadAndBlockDemo[2153:12303] dispatch_async3
如果使用dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);會發現運行結果為:
2013-07-24 17:07:17.577 NSThreadAndBlockDemo[2247:12e03] dispatch_barrier_async 2013-07-24 17:07:18.579 NSThreadAndBlockDemo[2247:15207] dispatch_async3 2013-07-24 17:07:19.578 NSThreadAndBlockDemo[2247:12b03] dispatch_async2 2013-07-24 17:07:20.577 NSThreadAndBlockDemo[2247:12303] dispatch_async1
說明dispatch_barrier_async的順序執行還是依賴queue的類型啊,必需要queue的類型為dispatch_queue_create創建的,而且attr參數值必需是DISPATCH_QUEUE_CONCURRENT類型,前面兩個非dispatch_barrier_async的類型的執行是依賴其本身的執行時間的,如果attr如果是DISPATCH_QUEUE_SERIAL時,那就完全是符合Serial queue的FIFO特征了。