多线程之GCD(Grand Central Dispatch)

GCD是纯C语言,但又溶有面向对象思想、基于Block。
1、GCD优点:

  • 易用:GCD比thread更简单易用,基于Block的特性导致它能极为简单的在不同代码作用域之间传递上下文。
  • 效率:GCD在很多地方比之专门创建消耗资源的线程更实用、快速。
  • 性能:GCD自动根据系统负载来增减线程数量,减少了上下文切换以及提高了计算效率。

2、GCD的使用

2.1.dispatch async异步操作

2.1.1.定义想要执行的操作(任务),追加到适当的队列中(Dispatch Queue)

2.12.Queue类型:
(1)Serial Dispatch Queue — 等待现在正在执行的任务处理结束(串行)
(2)Concurrent Dispatch Queue — 不等待现在正在执行的任务处理结束(并行、并发)

2.1.3.自己定义queue,把任务加到自定义的queue之中

(1)创建queue

 //第一个参数:给队列起名字
 //第二个参数:queue的类型 (默认是串行的)
    dispatch_queue_t queue1 = dispatch_queue_create("com.wxhl.gcd.Queue1", NULL);

    dispatch_queue_t queue2 = dispatch_queue_create("com.wxhl.gcd.Queue2", DISPATCH_QUEUE_CONCURRENT);  //并行的queue

(2)创建要执行的任务,加到queue中执行

 dispatch_async(queue2, ^{
        for (int i = 0; i < 50; i ++) {
            NSLog(@"GCD : %d", i);
        }
    });

2.1.4.使用系统给提供的queue(推荐)
两种
Main Dispatch Queue Global Dispatch Queue
串行(主线程) 并行

 //main
    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    dispatch_async(mainQueue, ^{
        ;
    });

    //global
    //参数一:优先级
    //参数二:标识符
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_async(globalQueue, ^{

        //请求网络数据

        //显示在UI界面上
        dispatch_async(dispatch_get_main_queue(), ^{
            //UI相关的代码
        });

    });

    //主线程
    for (int i = 0; i < 50; i ++) {
        NSLog(@"主线程 : %d", i);
    }
//async: asynchronous 将任务异步的追加到队列中
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"async");
    });

2.2 dispatch sync同步操作

 //sync: synchronous 将任务同步的追加到队列中(等队列中的任务执行完,再将任务追加到队列)
    //是同步追加,不是任务同步执行,在串行队列中,任务才同步执行
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"sync");
    });


   **dispatch_sync的问题:容易产生死锁**
    示例1:

    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"hello");
    });

    NSLog(@"主线程");

    //上述代码在主队列中执行指定的block,等待其执行结束
    //而主队列中本来就在执行上述代码,无法执行追加的block

    示例2:

    //串行的队列
    dispatch_queue_t queue = dispatch_queue_create("com.wxhl.GCD.queue", NULL);
    dispatch_async(queue, ^{
        dispatch_sync(queue, ^{
            NSLog(@"串行队列");
        });
    });

3. GCD高级用法
3.1 Dispatch After
一段时间之后,把要执行的任务追加到队列当中

- (void)viewDidLoad {
    [super viewDidLoad];

    //创建时间
    //相对的时间点     相对第一个参数多长时间之后
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC);

    //时间的单位
    //NSEC_PER_SEC   秒
    //NSEC_PER_MSEC  毫秒
    //NSEC_PER_USEC  微秒

    //dispatch_time_t 指定的时间
    dispatch_after(time, dispatch_get_main_queue(), ^{
        NSLog(@"after 3s");
    });

    //第二种用法
    dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC), dispatch_get_main_queue(), NULL, func1);


    //自己使用
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5ull * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        ;
    });

#warning 注意
    //1.不是一段时间之后执行相应的任务 (而是把要执行的任务追加到队列当中)
    //2.主线程 runloop 1/60秒检测事件, 追加的时间范围 3s - (3 + 1/60)s


}

void func1()
{

}

@end

3.2 Dispatch Group
dispatch_group_async :使用 group 监视 队列任务的执行
dispatch_group_notify:所有任务执行结束汇总,不阻塞当前线程
dispatch_group_wait: 等待直到所有任务执行结束,中途不能取消,阻塞当前线程

- (void)viewDidLoad {
    [super viewDidLoad];

 //1.创建 group
    dispatch_group_t group = dispatch_group_create();

    //2.获取队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    //3.使用 group 监视 队列任务的执行
    dispatch_group_async(group, queue, ^{
        NSLog(@"task 1");
    });

    dispatch_group_async(group, queue, ^{
        NSLog(@"task 2");
    });

    dispatch_group_async(group, queue, ^{
        NSLog(@"task 3");
    });

    dispatch_group_async(group, queue, ^{
        sleep(6);
        NSLog(@"task 4");
    });


    //(1)监视的函数
    //监视到队列里任务执行结束,执行block里面的任务
    dispatch_group_notify(group, queue, ^{
        //结束处理
        NSLog(@"done");
    });


    //(2)

    //等待time时间,根据wait函数的返回值确定队列中任务是否执行结束,5秒后汇总结果,不管任务有没有执行完
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC);

    //dispatch_group_wait 指定的时间之后 看一眼queue的任务是否执行完毕
    //如果执行完,返回0
    //如果没有执行完,返回非0值
    long result = dispatch_group_wait(group, time);
    if (result == 0) {
        NSLog(@"finish");
    } else {
        NSLog(@"not finish");
    }

    //dispatch_group_wait 会堵塞当前线程 一直在调用这个函数 等待指定的时间之后才会返回

 sleep(2);
    NSLog(@"main");
}

@end

3.3 dispatch once实现单例

ViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];

    //dispatch once
    //保证block里的任务只执行一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"只会执行一次");
    });  
}

@end

AddressBook.m

#import "AddressBook.h"

static AddressBook *instance = nil;

@implementation AddressBook
/*
 * 单例  单例模式  尽量不要使用
 * 1.含义:一个类只创建一个对象
 * 2.生命周期:从创建开始,应用程序退出结束
 * 3.取得单例对象的方法,命名规则: share default
 * 4.内存管理尽量由该类来管理
 */

+ (AddressBook *)sharedInstance
{
 //onceToken 标记block里的代码是否执行过
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[AddressBook alloc] init];
    });

    return instance;
}
//alloc 会自动调用 allocWithZone:
//zone 空间 分配内存空间(zone),创建对象
+ (id)allocWithZone:(NSZone *)zone
{
    if (instance == nil) {
        instance = [super allocWithZone:zone];
    }
    return instance;
}
@end

4. 小结:

  • 安全:无需加锁或其他同步机制。
  • 充分利用多核
  • 所有多线程代码集中在一起,便于维护
  • GCD中无需实用@autoreleasepool
  • 如果要顺序执行,可以使用dispatch_sync同步方法(dispatch_sync无法确定任务的执行顺序)
  • 调用主线程队列任务更新UI时,最好使用同步方法
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值