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

你可能感兴趣的:(多线程,并发,异步,gcd)