iOS GCD完全解析

-、GCD(Grand Central Dispatch)

OS X Snow Leopard / iOS4

异步执行任务的技术之一

简洁(封装)高效(C/系统级 XNU内核)

体验一下:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //新的线程中执行
        NSLog(@"working");
        dispatch_async(dispatch_get_main_queue(), ^{
            //主线程中执行
            NSLog(@"done");
        });
    });

二、多线程

多条无分叉路径 “上下文切换”

缺点:数据竞争 死锁 消耗大量内存

优点:防止阻塞主线程 提高执行效率 (NSRunLoop)

三、GCD的API

1、Dispatch Queue

1)定义

执行处理的等待队列(FIFO);

两类Dispatch Queue:Serial Dispatch Queue(串行队列) 和 Concurrent Dispatch Queue(并行队列)

两种队列的区别:

Serial Dispatch Queue:只创建一个线程;按照FIFO取Block分配给一个线程处理;有等待,顺序执行;

Concurrent Dispatch Queue:创建多个线程;按FIFO取Block分配给多个线程处理;无等待,同时执行;(注:线程树由XNU内核决定)

2)创建

//并行队列
dispatch_queue_t concurrent = dispatch_queue_create("com.study.gcd.CONCURRENT_QUEUE", DISPATCH_QUEUE_CONCURRENT);
//串行队列
dispatch_queue_t serial = dispatch_queue_create("com.study.gcd.SERIAL_QUEUE", DISPATCH_QUEUE_SERIAL/*NULL*/);
//多个串行队列可并行执行
//释放
//dispatch_release(serial);
//dispatch_retain(serial);

3)两个特殊的Dispatch Queue

dispatch_queue_t main = dispatch_get_main_queue();//串行队列 主线程队列(可用于更新界面)
dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//并行队列(系统提供的全局队列)

优先级:DISPATCH_QUEUE_PRIORITY_HIGHT > DISPATCH_QUEUE_PRIORITY_DEFAULT > DISPATCH_QUEUE_PRIORITY_LOW > DISPATCH_QUEUE_PRIORITY_BACKGROUND

2、dispatch_set_target_queue

作用:变更dispatch_queue的执行优先级;设置dispatch_queue的执行层次;

dispatch_queue_create函数生成的dispatch queue(无论是串行还是并行)的优先级都与global dispatch queue的默认优先级相同;

变更方法(生成一个后台级的串行队列):

dispatch_queue_t background = dispatch_queue_create(“com.study.gcd.BACKGROUND_QUEUE”, NULL);
dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_set_target_queue(background, global);
//可以通过指定dispatch_set_target_queue来使多个Serial Dispatch Queue按照层级串行执行

3、dispatch_after

作用:指定多长时间后追加block到queue

使用方法:

dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{
	NSLog(@“waited at least 3 seconds”);
});
//注意:并不是3秒后执行,而是三秒后加入队列,如果RunLoop每隔1/60s执行一次,那么上面的log最快3s执行,最慢(3+1/60)s执行
dispatch_time_t的获取:
//1 第一种方法 dispatch_time
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);
//2 第二种方法 dispatch_walltime//日期到dispatch time
dispatch_time_t get_time_by_date(NSDate * date)  {
    dispatch_time_t time;
    
    NSTimeInterval interval = [date timeIntervalSince1970];
    
    double second, nsecond;
    nsecond = modf(interval, &second);
    
    struct timespec spec;
    spec.tv_sec = second;
    spec.tv_nsec = nsecond;
    
    time = dispatch_walltime(&spec, 0);
    
    return time;
}

4、dispatch_group

作用:在执行完dispatch queue里所有的任务后执行结束处理或者在执行完所有的dispatch queue后执行结束处理

使用方法:

dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, global, ^{
        NSLog(@"1---");
    });
    dispatch_group_async(group, global, ^{
        NSLog(@"2---");
    });
    dispatch_group_async(group, global, ^{
        NSLog(@"3---");
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"all done");
    });
//上述的dispatch_group_notify可以换成dispatch_group_wait 所在线程会停止直到返回(阻塞)
//永久等待
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
//等待5s
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 5ull * NSEC_PER_SEC);
long result = dispatch_group_wait(group, time);
if(result == 0) {
	//dispatch group全部处理
}else {
	//dispatch group还有在执行
}

5、dispatch_barrier_async

作用:实现并行中的串行执行;如:前两个任务并行执行完后,开始执行第三个特殊任务,第三个特殊任务执行完后,并行执行第四第五个任务;

使用方法:

dispatch_queue_t concurrent = dispatch_queue_create("com.study.gcd.CONCURRENT_QUEUE", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(concurrent, ^{
        NSLog(@"第一个任务");
        [NSThread sleepForTimeInterval:3];
    });
    dispatch_async(concurrent, ^{
        NSLog(@"第二个任务");
    });
    dispatch_barrier_sync(concurrent, ^{
        NSLog(@"第三个特殊任务");
    });
    NSLog(@"hi");
    dispatch_async(concurrent, ^{
        NSLog(@"第四个任务");
    });
    dispatch_async(concurrent, ^{
        NSLog(@"第五个任务");
    });

注意:会阻塞当前线程

6、dispatch_sync/dispatch_async

dispatch_sync:同步任务 阻塞当前线程

dispatch_async:异步任务 不阻塞当前线程

死锁代码:

dispatch_sync(dispatch_get_main_queue(), ^{NSLog(@“死锁");});

7、dispatch_apply

作用:按指定次数将指定的block追加到dispatch queue,并等待全部执行结束(阻塞);

使用方法:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(10, queue, ^(size_t index) {
        NSLog(@"%zu", index);
    });
    NSLog(@"dispatch apply done”);
推荐用法:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        dispatch_apply(10/*[array count]*/, queue, ^(size_t index) {
            NSLog(@"%zu", index);
        });
        
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"update ui");
        });
    });

8、dispatch_suspend/dispatch_resume/dispatch_once

作用:挂起和恢复dispatch_queue;保证只执行一次;
dispatch_suspend(queue);
dispatch_resume(queue);
static dispatch_once_t once;
dispatch_once(&once, ^{
	NSLog(@“只执行一次”);
});

9、dispatch_semaphore

作用:执行更细粒度的排他控制,也即是更精度的顺序控制(信号量机制);

使用方法:

dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    NSMutableArray * array = [NSMutableArray array];
    for (int i = 0; i< 100000; i++) {
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        [array addObject:[NSNumber numberWithInt:i]];
        dispatch_semaphore_signal(semaphore);
    }

10、dispatch_io

作用:分块读取大文件

使用方法:

dispatch_io 和 dispatch_data配合使用

四、GCD实现

1、用于管理block的c语言层实现的FIFO队列

2、Atomic函数中实现的用于拍他的轻量级信号

3、用于管理线程的C语言层实现的容器

4、内核XNU上的实现

dispatch_queue(libdispatch)

pthread_workqueue(libc)

workqueue(XNU内核)

block先加入到dispatch_continuation_t(上下文)然后再加入到dispatch queue

high priority -> pthread_workqueue -> WORKQUEUE_HIGH_PRIOQUEUE

default priority -> pthread_workqueue -> WORKQUEUE_DEFAULT_PRIOQUEUE

low priority -> pthread_workqueue -> WORKQUEUE_LOW_PRIOQUEUE

background priority -> pthread_workqueue -> WORKQUEUE_BG_PRIOQUEUE

high overcommit priority -> pthread_workqueue -> WORKQUEUE_HIGH_PRIOQUEUE

default overcommit priority -> pthread_workqueue -> WORKQUEUE_DEFAULT_PRIOQUEUE

low overcommit priority -> pthread_workqueue -> WORKQUEUE_LOW_PRIOQUEUE

background overcommit priority -> pthread_workqueue -> WORKQUEUE_BG_PRIOQUEUE

附:dispatch source

DISPATCH_SOURCE_TYPE_DATA_ADD

DISPATCH_SOURCE_TYPE_DATA_OR

DISPATCH_SOURCE_TYPE_MACH_SEND

DISPATCH_SOURCE_TYPE_MACH_RECV

DISPATCH_SOURCE_TYPE_PROC

DISPATCH_SOURCE_TYPE_READ

DISPATCH_SOURCE_TYPE_SIGNAL

DISPATCH_SOURCE_TYPE_TIMER

DISPATCH_SOURCE_TYPE_VNODE

DISPATCH_SOURCE_TYPE_WRITE

dispatch_queue没有取消的概念(不能取消除非自己处理)

dispatch_source可以取消

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柠檬李先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值