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