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); } });