多线程之GCD(Grand Central Dispatch)

来源:互联网 发布:首届江苏网络 编辑:程序博客网 时间:2024/05/16 18:43

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
原创粉丝点击