多线程 —— GCD

来源:互联网 发布:seo实战密码 epub 编辑:程序博客网 时间:2024/04/30 09:42
什么是GCD
全称是Grand Central Dispatch,可译为“牛逼的中枢调度器”
C语言,提供了非常多强大的函数

GCD的优势
GCD是苹果公司为多核并行运算提出的解决方案
GCD会自动利用更多的CPU内核(比如双核、四核)
GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码

GCD中有2个核心概念
任务执行什么操作
队列:用来存放任务

GCD的使用就2个步骤
1、定制任务:确定想做的事情
2、将任务添加到队列
GCD会自动将队列中的任务取出,放到对应的线程中执行
任务的取出遵循队列FIFO原则:先进先出,后进后出

执行任务
GCD中有2个用来执行任务的函数
同步的方式执行任务

dispatch_sync(dispatch_queue_t  queue, dispatch_block_t  block);

queue:队列
block:任务
异步的方式执行任务

dispatch_async(dispatch_queue_t  queue,dispatch_block_t  block);

同步和异步的区别
同步:在当前线程中执行
异步:在另一条线程中执行

队列的类型
GCD的队列可以分为2大类型
并发队列(Concurrent Dispatch Queue
可以让多个任务并发同时)执行自动开启多个线程同时执行任务)
并发功能只有在异步dispatch_async)函数下才有效
串行队列(Serial Dispatch Queue
让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)

容易混淆的术语
同步异步决定了要不要开启新的线程
同步:在当前线程中执行任务,不具备开启新线程的能力
异步:在新的线程中执行任务,具备开启新线程的能力

并发串行决定了任务的执行方式
并发多个任务并发(同时)执行
串行一个任务执行完毕后,再执行下一个任务

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
四种组合方式:
1、串行队列,同步执行任务
<span style="font-size:18px;"><span style="font-size:18px;">// 1. 创建一个串行队列    //参数:1. 队列标签 2. 队列的属性    dispatch_queue_t queue = dispatch_queue_create("itcast", DISPATCH_QUEUE_SERIAL);        NSLog(@"开始!!");    // 2. 同步执行任务    // 一般只要使用”同步“执行,串行队列对添加的同步任务,会立马执行    dispatch_sync(queue, ^{        NSLog(@"%@", [NSThread currentThread]);    });</span></span>

2、串行队列,异步(开启多个线程)执行任务
<span style="font-size:18px;"><span style="font-size:18px;"> // 1. 串行队列    // 下面两种写法是一样的//    dispatch_queue_t queue = dispatch_queue_create("itcast", DISPATCH_QUEUE_SERIAL);    dispatch_queue_t queue = dispatch_queue_create("itcast", NULL);        // 2. 异步执行    for (int i = 0; i < 10; i++) {        dispatch_async(queue, ^{            NSLog(@"%@ %d", [NSThread currentThread], i);        });    }</span></span>

3、并行队列,同步执行任务
<span style="font-size:18px;"><span style="font-size:18px;">//1. 并行队列    dispatch_queue_t queue = dispatch_queue_create("cz", DISPATCH_QUEUE_CONCURRENT);        // 2. 同步执行任务    for (int i = 0; i < 10; i++) {        dispatch_sync(queue, ^{            NSLog(@"%@ %d", [NSThread currentThread], i);        });    }</span></span>

4、并行队列,异步执行任务
<span style="font-size:18px;"><span style="font-size:18px;"> //1. 并行队列    dispatch_queue_t queue = dispatch_queue_create("cz", DISPATCH_QUEUE_CONCURRENT);        // 2. 异步执行任务    for (int i = 0; i < 10; i++) {        dispatch_async(queue, ^{            NSLog(@"%@ %d", [NSThread currentThread], i);        });    }</span></span>


主队列:
<span style="font-size:18px;">/** 主队列:专门负责在主线程上调度任务,不会在子线程调度任务,在主队列不允许开新线程. 异步执行: 会开新线程,在新线程执行 结果: 不开线程, 只能在主线程上面,顺序执行! */- (void)gcdTest5{    // 1. 获得主队列-> 程序启动,--> 至少有一个主线程-> 一开始就会创建主队列    dispatch_queue_t queue = dispatch_get_main_queue();        NSLog(@"1----");        // 2. 异步执行任务    for (int i = 0; i < 10; i++) {        NSLog(@"调度前---");        // 异步:把任务放到主队列里,但是不需要马上执行        dispatch_async(queue, ^{            NSLog(@"%@ %d", [NSThread currentThread], i);        });        NSLog(@"睡会");        [NSThread sleepForTimeInterval:2.0];    }    NSLog(@"完成----");}</span>

/**

 主队列:专门负责在主线程上调度任务,不会在子线程调度任务,在主队列不允许开新线程.

 同步执行:要马上执行

 结果:死锁

 */


同步任务的作用
<span style="font-size:18px;">#pragma GCD- 同步任务的作用- (void)gcdTest7{    // 并发队列    dispatch_queue_t  queue = dispatch_queue_create("cz", DISPATCH_QUEUE_CONCURRENT);        /**     例子:有一个小说网站     - 必须登录,才能下载小说          有三个任务:     1. 用户登录     2. 下载小说A     3. 下载小说B     */    // 添加任务    // 同步任务,需要马上执行。 不开新线程    dispatch_sync(queue, ^{        NSLog(@"用户登录 %@", [NSThread currentThread]);    });    //    dispatch_async(queue, ^{        NSLog(@"下载小说A %@", [NSThread currentThread]);    });    dispatch_async(queue, ^{        NSLog(@"下载小说B %@", [NSThread currentThread]);    });}</span>

全局队列:也是并发队列
/** 全局队列跟并发队列的区别 1. 全局队列没有名称 并发队列有名称 2. 全局队列,是供所有的应用程序共享。 3. 在MRC开发,并发队列,创建完了,需要释放。 全局队列不需要我们管理 */#pragma CGD - 全局队列- (void)gcdTest8{    // 获得全局队列    /**     参数:第一个参数,一般 写 0(可以适配 iOS 7 & 8)     iOS 7     DISPATCH_QUEUE_PRIORITY_HIGH 2  高优先级     DISPATCH_QUEUE_PRIORITY_DEFAULT 0  默认优先级     DISPATCH_QUEUE_PRIORITY_LOW (-2) 低优先级     DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN 后台优先级          iOS 8     QOS_CLASS_DEFAULT  0          第二个参数:保留参数 0     */    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);        // 添加异步任务    for (int i = 0; i < 10; i++) {        dispatch_async(queue, ^{            NSLog(@"%@ %d", [NSThread currentThread], i);        });    }    }

 队列的选择:

 串行队列异步执行

 -  开一条线程,顺序执行

 -  效率:不高,执行比较慢,资源占用小 -省电

 

 一般网络是3G,对想能要求不会很高。

 

 并发队列异步执行

 - 开启多条线程,并发执行

 - 效率:高,执行快,资源消耗大-》费电

 使用场合:

 - 网络WiFi,或者需要很快的响应,要求用户体验非常流畅。

 -对任务执行顺序没有要求

 

 -同步任务:一般只会在并发队列,需要阻塞后续任务。必须等待同步任务执行完毕,再去执行其他任务。"依赖"关系


线程间的通讯:(重点)
<span style="font-size:18px;">- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {        dispatch_async(dispatch_get_global_queue(0, 0), ^{                NSLog(@"%@", [NSThread currentThread]);        // 耗时操作: 放在全局队列,异步执行        // 1. url, 确定一个网络上的资源路径        NSURL *url = [NSURL URLWithString:@"http://fe.topit.me/e/d1/12/1170068721aa112d1el.jpg"];                // 2. 通过url可以下载对应的网络资源, 网络资源传输的都是二进制        NSData *data = [NSData dataWithContentsOfURL:url];                // 3. 二进制转成图片        UIImage *image = [UIImage imageWithData:data];                // 4. 更新UI,在主线程-》 直接把任务添加到主队列,就会在主队列执行        dispatch_async(dispatch_get_main_queue(), ^{            self.iconView.image = image;            NSLog(@"-----%@", [NSThread currentThread]);        });    });    }</span>

其他用法:
<span style="font-size:18px;">#pragma mark - 调度组(分组)- (void)group{    /**     应用场景:     开发的时候,有的时候出现多个网络请求都完成以后(每一个网络请求的事件长短不一定),再统一通知用户                比如: 下载小说:三国演义, 红楼梦, 金X梅     */    // 实例化一个调度组    dispatch_group_t group = dispatch_group_create();        // 队列    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);        // 任务添加到队列queue    dispatch_group_async(group, queue, ^{        NSLog(@"下载小说A---%@", [NSThread currentThread]);    });        dispatch_group_async(group, queue, ^{        NSLog(@"下载小说B---%@", [NSThread currentThread]);    });        dispatch_group_async(group, queue, ^{        NSLog(@"下载小说X---%@", [NSThread currentThread]);    });        // 获得所有调度组里面的异步任务完成的通知//    dispatch_group_notify(group, queue, ^{//        NSLog(@"下载完成,请观看%@", [NSThread currentThread]); // 异步的//    });    //注意点: 在调度组完成通知里,可以跨队列通信    dispatch_group_notify(group, dispatch_get_main_queue(), ^{        // 更新UI,在主线程        NSLog(@"下载完成,请观看%@", [NSThread currentThread]); // 异步的    });}</span>

延时执行:
<span style="font-size:18px;"> dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{        NSLog(@"点我了-- %@", [NSThread currentThread]);    });</span>

一次性任务:
<span style="font-size:18px;"> dispatch_once(&onceToken, ^{        NSLog(@"%----ld", onceToken);        NSLog(@"真的执行一次么?");    });</span>

0 0