1. 程式人生 > >GCD 多線程技術

GCD 多線程技術

array 在線 rand wait 信號 效率 The loop ron

Grand Central Dispatch(GCD)是異步執行任務的技術之一。一般將應用程序中記述的線程管理用

的代碼在系統級中實現。開發者只需要定義想執行的任務並追加到適當的Dispatch Queue中,DCD就能生成

必要的線程並計劃執行任務。由於線程管理是作為系統的一部分來實現的,因此可以統一管理,也可以執行任務,

這樣就比以前的線程更有效率。

GCD API

1. Dispatch Queue 隊列

隊列有兩種類型:

Serial Dispatch Queue 串行隊列,使用一個線程,按照追加的順序(先進先出FIFO)執行處理。多個串行隊列之間是並行處理的。
Concurrent Dispatch Queue 並行隊列,使用多個線程,並發處理

2.diapatch_queue_create

創建 Serial Queue:

dispatch_queue_t mySerailQueue = dispatch_queue_create("com.r.dispatchSerailQueue", DISPATCH_QUEUE_SERIAL);

dispatch_queue_t myConcurrentQueue = dispatch_queue_create("com.r.dispatchConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);

第一個參數是指定 Serial dispatch queue 的名稱。該名稱在Xcode和Instruments的調試器中作為Dispatch Queue名稱.

第二個參數是生成Dispatch Queue的類型,如果是NULL 或者 DISPATCH_QUEUE_SERIAL生成串行隊列,

指定為DISPATCH_QUEUE_CONCURRENT生成並發隊列.

3.Main Dispatch Queue/Global Dispatch Queue

獲取系統標準提供的Dispatch Queue。

Main Dispatch Queue是在主線程執行的dispatch queue, Main Dispatch Queue是一個Serail Dispatch Queue。追加到Main Dispatch Queue的處理在主線程的RunLoop中執行。一般將用戶界面更新等必需要在主線程中執行的處理追加到Main Dispatch Queue中。

Global Dispatch Queue是所有應用程序都能過使用的Concurrent Dispatch Queue。沒有必要通過dispatch_queue_create函數逐個創建Concurrent Dispatch Queue,只要獲取Global Dispatch Queue使用即可。Global Dispatch Queue有四個優先級

名稱Dispatch Queue的種類說明
Main Dispatch Queue Serial Dispatch Queue 主線程執行
Global Dispatch Queue(High Priority) Concurrent Dispatch queue 執行優先級:高(最高)
Global Dispatch Queue(Default Priority) Concurrent Dispatch queue 執行優先級:默認
Global Dispatch Queue(Low Priority) Concurrent Dispatch queue 執行優先級:低
Global Dispatch Queue(Background Priority) Concurrent Dispatch queue 執行優先級:後臺

獲取Dispatch Queue方法:

dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();

dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

使用Main Dispatch Queue 和 Global Dispatch Queue

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        /**
         *  可並行處理的任務TODO
         */

        dispatch_async(dispatch_get_main_queue(), ^{
            /**
             *  主線程執行
             */
        });
    });



4. dispatch_after

dispatch_after表示在指定的時間之後追加處理到Dispatch Queue。並不是指定時間後執行處理。

dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull*NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{
        NSLog(@"等待3秒後執行");
 });

雖然在有嚴格時間到要求下使用時會出現問題,但在大致延遲執行處理時,該函數還是有效的。

5.dispatch_suspend/dispatch_resume

當追加大量處理到Dispatch Queue時,在追加處理到過程中,有時希望不執行已追加的處理。在這種情況下只要掛起Dispatch Queue即可。

dispatch_suspend 函數掛起指定的Dispatch Queue

dispatch_resume 函數恢復指定的Dispatch Queue

這些函數對已經執行的處理沒有影響,掛起後,追加到Dispatch Queue中處理在此之後暫停執行,而恢復使得這些處理繼續執行。

6.Dispatch Group

在追加到Dispatch Queue中的多個處理全部結束後想執行結束處理.

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, ^{
        for (int i=0; i<2000; i++) {
            NSLog(@"111111");
        }
    });
    dispatch_group_async(group, queue, ^{
        for (int i=0; i<2000; i++) {
            NSLog(@"2222222");
        }
    });
    dispatch_group_async(group, queue, ^{
        for (int i=0; i<2000; i++) {
            NSLog(@"33333");
        }
    });
    //最後執行4444
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"44444");
    });
    NSLog(@"555555");

7. dispatch_barrier_async

   dispatch_async(queue, ^{
        //讀文件
    });
    dispatch_async(queue, ^{
         //讀文件
    });

    //使用dispatch_barrier_async避免數據競爭
    dispatch_barrier_async(queue, ^{
        //寫文件
    });
    dispatch_async(queue, ^{
        //讀文件
    });
    dispatch_async(queue, ^{
        //讀文件
    });

一個dispatch barrier 允許在一個並發隊列中創建一個同步點。當在並發隊列中遇到一個barrier, 他會延遲執行barrier的block,

等待所有在barrier之前提交的blocks執行結束。 這時,barrier block自己開始執行。 之後, 隊列繼續正常的執行操作。

調用這個函數總是在barrier block被提交之後立即返回,不會等到block被執行。當barrier block到並發隊列的最前端,

他不會立即執行。相反,隊列會等到所有當前正在執行的blocks結束執行。到這時,barrier才開始自己執行。

所有在barrier block之後提交的blocks會等到barrier block結束之後才執行

這裏指定的並發隊列應該是自己通過dispatch_queue_create函數創建的。

如果你傳的是一個串行隊列或者全局並發隊列,這個函數等同於dispatch_async函數。

8.dispatch_apply

dispatch_apply函數是dispatch_sync函數和Dispatch Group的關聯API。

該函數按指定的次數將指定的Block追加到Dispatch Queue中,並等待全部處理執行結束。

1 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2     dispatch_apply(10, queue, ^(size_t index) {
3         NSLog(@"%zu", index);//並行
4     });
5     //最後執行
6     NSLog(@"11");

9. Dispatch Semaphore

信號量:就是一種可用來控制訪問資源的數量的標識,設定了一個信號量,在線程訪問之前,加上信號量的處理,則可告知系統按照我們指定的信號量數量來執行多個線程。

 1 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
 2     
 3     /**
 4      * 生成Dispatch Semaphore
 5      * Dispatch Semaphore 的計數初始值設定為1
 6      * 保證可訪問NSMutableArray類對象的線程同時只有一個
 7      */
 8     dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
 9     NSMutableArray *array = [[NSMutableArray alloc] init];
10     
11     for (int i=0; i<10000; i++) {
12         dispatch_async(queue, ^{
13             /**
14              *  等待Dispatch Semaphore
15                 一直等待,直到Dispatch Semaphore 的計數的值達到大於等於1
16              */
17             dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
18             
19             /**
20              *  由於Dispatch Semaphore 的計數達到大於等於1
21              所以Dispatch Semaphore 的計數值減去1
22              dispatch_semaphore_wait函數執行返回
23              
24              即執行到此時Dispatch Semaphore的計數值恒為00
25              
26              由於可訪問NSMutableArray類對象的線程數只有1個
27              因此可安全的進行更新
28              */
29             [array addObject:[NSNumber numberWithInt:i]];
30             
31             /**
32              * 排他控制處理結束
33              所以通過dispatch_semaphore_signal函數
34              將DispatchSemaphore的計數值加1
35              如果有通過dispatch_semaphore_wait函數
36              等待Dispatch Semaphore的計數值增加的線程
37              就由最先等待的線程執行。
38              */
39             dispatch_semaphore_signal(semaphore);
40         });
41     }

GCD 多線程技術