ios多线程之GCD(Grand Central Dispatch)

来源:互联网 发布:mac怎么删除软件快捷键 编辑:程序博客网 时间:2024/04/30 05:23

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 Queuedispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();// 获取Global Dispatch Queuedispatch_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 Prioritydispatch_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值达到大于等于110         dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);11         // 由于Dispatch semaphore的计数值达到大于等于112         // 所以将Dispatch semaphore的计数值减113         // dispatch_semaphore_wait函数执行返回14         // 即执行到此时的Dispatch semaphore计数值恒为015         // 由于可访问NSMutableArray类对象的线程只有一个16         // 因此可安全进行更新17         [array addObject:[NSNumber numberWithInt:i]];18         // 排他控制处理结束19         // 所以通过dispatch_semaphore_signal函数20         // 将Dispatch semaphore的计数值加121         // 如果有通过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);    }});
0 0