GCD(Grand Central Dispatch)


1. GCD: 異步執行任務的技術之一,一般是將應用程序中記述的線程管理用代碼在系統級實現,由於是系統級的管理,這樣的話將有更好的線程效率。

2. 使用方法如下:

dispatch_async(queue, ^{
    // 想執行的任務
});

開發者要做的只是定義想執行的任務並追加到適當的Dispatch Queue中。

3. 線程(Thread): 1個CPU執行的CPU指令列為一條無分叉路徑。

4. Dispatch Queue分為兩種:

  a. Serial Dispatch Queue: 線性執行的線程隊列,遵循FIFO(First In First Out)原則;

  b. Concurrent Dispatch Queue: 並發執行的線程隊列,並發執行的處理數取決於當前狀態。

// 線性執行線程隊列
dispatch_queue_t serialQueue = dispatch_queue_create("com.mark.serialQueue", NULL);
dispatch_async(serialQueue, ^{
    NSLog(@"block on serialQueue");
});
dispatch_release(serialQueue);

// 並發執行線程隊列
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.mark.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue, ^{
    NSLog(@"block on concurrentQueue");
});
dispatch_release(concurrentQueue);

5. 系統的Dispatch Queue:

  a. Main Dispatch Queue: 主線程隊列(Serial Queue), 在程序的RunLoop中執行。

  b. Global Dispatch Queue: 系統中所有應用程序共用的全局隊列(Concurrent Queue), 一般不必創建新的Dispatch Queue,使用此Queue就可以了。

Global Diapacth Queue有4個優先級:High Priority(高)、Default Priority(默認)、Low Priority(低)、Background Priority(后台)。

// 獲取Main Dispatch Queue
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
// 獲取Global Dispatch Queue
dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_queue_t globalDispatchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_queue_t globalDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
// 常用示例
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 可執行並發處理
    
    dispatch_async(dispatch_get_main_queue(), ^{
        // 執行主線程更新操作    
    });
});

6. 關於自定義生成的Dispatch Queue優先級:首先dispatch_queue_create()生成的Dispatch Queue與默認Global Dispatch Queue具有相同的Priority,要改變Dispatch Queue的優先級則要使用dispatch_set_target_queue函數:

// 改變serialQueue(Default Priority)優先級為Background Priority
dispatch_queue_t serialQueue = dispatch_queue_create("com.mark.serialQueue", NULL);
dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_set_target_queue(serialQueue, globalDispatchQueueBackground);

7. Dispatch Queue的延遲執行:dispatch_after():

// 2秒后將指定的Block增加到指定的Dispatch Queue中
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    NSLog(@"Waitted at least 2 seconds");
});

8. 多個Dispatch Queue執行結束后的執行操作: Dispatch Group

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, ^{
    NSLog(@"Queue One");
});
dispatch_group_async(group, queue, ^{
    NSLog(@"Queue Two");
});
dispatch_group_async(group, queue, ^{
    NSLog(@"Queue Three");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    NSLog(@"Queues Done");
});
// 也可以這樣執行,每二參數用於表示超時時間
//dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull *NSEC_PER_SEC);
long result = dispatch_group_wait(group, time);
if (0 == result) {
// 屬於Dispatch Group的全部處理執行結束
}
else {
// 屬於Dispatch Group的某一個處理在超過指定時限后還在執行中
}
dispatch_release(group);

 // 不過還是提推薦使用dispatch_group_notify

9. 關於讀寫的數據同步操作,為處理數據而作:dispatch_barrier_async()

dispatch_queue_t queue = dispatch_queue_create("com.mark.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, bk_0_for_reading);
dispatch_async(queue, bk_1_for_reading);
dispatch_async(queue, bk_2_for_reading);
dispatch_async(queue, bk_3_for_reading);
// 以上的並發隊列中執行的都是讀任務,並不涉及到數據沖突問題(數據可以被多線程同時讀取,並發用於提高效率,並不影響數據)
// 接下就是要寫入數據后再執行相關的下半部的並發隊列任務
dispatch_barrier_async(queue, bk_for_writing);
// 繼續下半部分的並發
dispatch_async(queue, bk_4_for_reading);
dispatch_async(queue, bk_5_for_reading);
dispatch_async(queue, bk_6_for_reading);

10. 可控制dispatch_async Block塊執行次數的Block API: dispatch_apply()

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10, queue, ^(size_t index){
    NSLog(@"%zu", index);
});
// Param1 : Block執行次數
// Param2 : Block追回的隊列
// Param3 : Block執行的次數索引
// 高效遍歷數據元素(無序遍歷)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply([array count], queue, ^(size_t index){
    NSLog(@"array element of index %d: %@", index, [array objectAtIndex:index]);
});

11. 線程隊列的掛起與執行:

// 掛起隊列
dispatch_suspend(queue);
// 恢復隊列執行
dispatch_resume(queue);

12. 更細粒度的排他控制:dispatch_semaphore

 1 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
 2 // Create dispatch_semaphore
 3 // semaphore value初始化為1
 4 // 保證可訪問NSMutableArray類對象的線程同時只有一個
 5 dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
 6 NSMutableArray *array = [[NSMutableArray alloc] init];
 7 for (int i = 0; i < 100000; i++) {
 8     dispatch_async(queue, ^{
 9         // Waiting for dispatch semaphore, 直到semaphore值達到大於等於1
10         dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
11         // 由於Dispatch semaphore的計數值達到大於等於1
12         // 所以將Dispatch semaphore的計數值減1
13         // dispatch_semaphore_wait函數執行返回
14         // 即執行到此時的Dispatch semaphore計數值恆為0
15         // 由於可訪問NSMutableArray類對象的線程只有一個
16         // 因此可安全進行更新
17         [array addObject:[NSNumber numberWithInt:i]];
18         // 排他控制處理結束
19         // 所以通過dispatch_semaphore_signal函數
20         // 將Dispatch semaphore的計數值加1
21         // 如果有通過dispatch_semaphore_wait函數等待Dispatch semaphore的
22         // 計數值增加的線程,由最先等待的線程執行
23         dispatch_semaphore_signal(semaphore);
24     });
25 }
26 dispatch_release(semaphore);

13. dispatch_once: 只執行一次指定處理的API

// dispatch_once函數簡化如下
static int initialized = NO;
if (NO == initialized) {
    // 初始化   
    initialized = YES;
}

// dispatch_once函數使用如下
static dispatch_once_t pred;
dispatch_once(&pred, ^{
    // 初始化,這里多用於單例的模式
});

14. Dispatch I/O:並發讀取文件數據,高效率讀取文件:

// 並發讀取文件原理
dispatch_async(queue, ^{/* 讀取0-8191字節*/});
dispatch_async(queue, ^{/* 讀取8192-16383字節*/});
dispatch_async(queue, ^{/* 讀取163784-24575字節*/});
dispatch_async(queue, ^{/* 讀取24576-32767字節*/});
dispatch_async(queue, ^{/* 讀取32768-40959字節*/});
dispatch_async(queue, ^{/* 讀取40960-49151字節*/});
dispatch_async(queue, ^{/* 讀取49152-57343字節*/});
dispatch_async(queue, ^{/* 讀取57344-65535字節*/});

// 實例代碼如下
dispatch_queue_t pipe_q = dispatch_queue_create("PipQ", NULL);
dispatch_io_t pipe_channel = dispatch_io_create(DISPATCH_IO_STREAM, fd, pip_q, &(int err){
    close(fd);
});

*out_fd = dfpair[1];
// 設定函數一次讀取的大小(分割大小)
dispatch_io_set_low_water(pipe_channel, SIZE_MAX);
dispatch_io_read(pipe_channel, 0, SIZE_MAX, pipe_q, ^{
    if (0 == err) {
        size_t len = dispatch_data_get_size(pipedata);
        if (len > 0) {
            const char *bytes = NULL;
            char *encoded;
            dispatch_data_t md = dispatch_data_create_map(pipedata, (const void **)&bytes, &len);
            encoded = asl_core_encode_buffer(bytes, len);
            asl_set((aslmsg)merged_msg, ASL_KEY_AUX_DATA, encoded);
            free(encoded);
            _asl_send_message(NULL, merged_msg, -1, NULL);
            _asl_msg_release(merged_msg);
            dispatch_release(md);
        }
    }
    if (done) {
        dispatch_semaphore_signal(sem);
        dispatch_release(pipe_channel);
        dispatch_release(pipe_q);
    }
});

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM