美文网首页
GCD的理解与使用

GCD的理解与使用

作者: 一个半吊子工程师 | 来源:发表于2018-10-10 14:49 被阅读0次

原文链接

GCD的特点

• GCD会自动利用更多的CPU内核
• GCD 可用于多核的并行运算
• GCD自动管理线程的生命周期(创建线程,调度任务,销毁线程等)
• 程序员只需要告诉 GCD 想要如何执行什么任务,不需要编写任何线程管理代码

GCD的基本概念

任务(block):任务就是将要在线程中执行的代码,将这段代码用block封装好,然后将这个任务添加到指定的执行方式(同步执行和异步执行),等待CPU从队列中取出任务放到对应的线程中执行。

同步(sync):一个接着一个,前一个没有执行完,后面不能执行,不开线程。

异步(async):开启多个新线程,任务同一时间可以一起执行。异步是多线程的代名词

队列:装载线程任务的队形结构。(系统以先进先出的方式调度队列中的任务执行)。在GCD中有两种队列:串行队列和并发队列。

并发队列: 线程可以同时一起进行执行。实际上是CPU在多条线程之间快速的切换。(并发功能只有在异步(dispatch_async)函数下才有效)

并发队列

串行队列: 线程只能依次有序的执行。


串行队列

GCD总结:将任务(要在线程中执行的操作block)添加到队列(自己创建或使用全局并发队列),并且指定执行任务的方式(异步dispatch_async,同步dispatch_sync)

队列的创建方法

• 使用dispatch_queue_create来创建队列对象,传入两个参数,第一个参数表示队列的唯一标识符,可为空。第二个参数用来表示串行队列(DISPATCH_QUEUE_SERIAL)或并发队列(DISPATCH_QUEUE_CONCURRENT)

// 串行队列
dispatch_queue_t queue =dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
  
// 并发队列
dispatch_queue_t queue1 =dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);

• GCD的队列还有另外两种:

主队列:主队列负责在主线程上调度任务,如果在主线程上已经有任务正在执行,主队列会等到主线程空闲后再调度任务。通常是返回主线程更新UI的时候使用。dispatch_get_main_queue()

  dispatch_async(dispatch_get_global_queue(0, 0), ^{
      // 耗时操作放在这里

      dispatch_async(dispatch_get_main_queue(), ^{
          // 回到主线程进行UI操作

      });
  });

全局并发队列:全局并发队列是就是一个并发队列,是为了让我们更方便的使用多线程。dispatch_get_global_queue(0, 0)

#参数:优先级 DISPATCH_QUEUE_PRIORITY_DEFAULT 始终是 0
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
#可同步 可异步
//全局并发队列
dispatch_queue_t queue = 
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

//全局并发队列的优先级
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高优先级
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)优先级
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低优先级
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台优先级
//iOS8开始使用服务质量,现在获取全局并发队列时,可以直接传0
dispatch_get_global_queue(0, 0);

同步/异步/任务、创建方式

同步(sync)使用dispatch_sync来表示。
异步(async)使用dispatch_async
任务就是将要在线程中执行的代码,将这段代码用block封装好。
代码如下:

 // 同步执行任务
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        // 任务放在这个block里
        NSLog(@"我是同步执行的任务");
 
    });
    // 异步执行任务
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        // 任务放在这个block里
        NSLog(@"我是异步执行的任务");
 
    });

GCD的使用

由于有多种队列(串行/并发/主队列)和两种执行方式(同步/异步),所以他们之间可以有多种组合方式。

• 串行同步
执行完一个任务,再执行下一个任务。不开启新线程。
• 串行异步
开启新线程,但因为任务是串行的,所以还是按顺序执行任务。
• 并发同步
因为是同步的,所以执行完一个任务,再执行下一个任务。不会开启新线程。顺序执行
• 并发异步
任务交替执行,开启多线程。结果为无序执行
• 主队列同步
如果在主线程中运用这种方式,则会发生死锁,程序崩溃。
• 主队列异步
在主线程中任务按顺序执行。

主队列同步造成死锁的原因:

  1. 如果在主线程中运用主队列同步,也就是把任务放到了主线程的队列中。
  2. 而同步对于任务是立刻执行的,那么当把第一个任务放进主队列时,它就会立马执行。
  3. 可是主线程现在正在处理syncMain方法,任务需要等syncMain执行完才能执行。
  4. syncMain执行到第一个任务的时候,又要等第一个任务执行完才能往下执行第二个和第三个任务。
  5. 这样syncMain方法和第一个任务就开始了互相等待,形成了死锁。

GCD线程之间的通讯

开发中需要在主线程上进行UI的相关操作,通常会把一些耗时的操作放在其他线程,比如说图片文件下载等耗时操作。
当完成了耗时操作之后,需要回到主线程进行UI的处理,这里就用到了线程之间的通讯。

- (IBAction)communicationBetweenThread:(id)sender {
 
    // 异步
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        // 耗时操作放在这里,例如下载图片。(运用线程休眠两秒来模拟耗时操作)
        [NSThread sleepForTimeInterval:2];
        NSString *picURLStr = @"URL";
        NSURL *picURL = [NSURL URLWithString:picURLStr];
        NSData *picData = [NSData dataWithContentsOfURL:picURL];
        UIImage *image = [UIImage imageWithData:picData];
 
        // 回到主线程处理UI
        dispatch_async(dispatch_get_main_queue(), ^{
            // 在主线程上添加图片
            self.imageView.image = image;
        });
    });
}

上面的代码是在新开的线程中进行图片的下载,下载完成之后回到主线程显示图片。

GCD栅栏

GCD延时执行

当需要等待一会再执行一段代码时,就可以用到这个方法了:dispatch_after

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 
(int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    // 5秒后异步执行
    NSLog(@"我已经等待了5秒!");
});

GCD实现代码只执行一次

使用dispatch_once能保证某段代码在程序运行过程中只被执行1次。可以用来设计单例。

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    NSLog(@"程序运行过程中我只执行了一次!");
});

GCD快速迭代

GCD有一个快速迭代的方法dispatch_applydispatch_apply可以同时遍历多个数字。

- (IBAction)applyGCD:(id)sender {
 
    NSLog(@"\n\n************** GCD快速迭代 ***************\n\n");
 
    // 并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
 
    // dispatch_apply几乎同时遍历多个数字
    dispatch_apply(7, queue, ^(size_t index) {
        NSLog(@"dispatch_apply:%zd======%@",index, 
        [NSThread currentThread]);
    });
}

队列函数的应用

1600001808570.jpg

站在巨人的肩膀上学习!如有侵权,请联系删除

相关文章

  • GCD理解与使用

    并行与并发: 1.并发:当有多线程操作时,如果系统只有一个cpu,根本不可能真正同时进行一个以上的线程,只能把cu...

  • GCD的理解与使用

    原文链接 GCD的特点 • GCD会自动利用更多的CPU内核• GCD 可用于多核的并行运算• GCD...

  • GCD的理解与使用

    No.1:GCD的特点 GCD 可用于多核的并行运算 GCD 会自动利用更多的 CPU 内核(比如双核、四核) G...

  • 多线程系列文章

    GCD基础篇 - 同步、异步,并发、并行的理解 GCD中级篇 - dispatch_group的理解及使用 dis...

  • NSOperation&NSOperationQueue

    概述 NSOperation是对``GCD的封装,完全面向对象,使用起来更好理解。NSOperation对应GCD...

  • GCD的理解和使用

    巧谈GCD字数4076 阅读1990 评论32 喜欢70谈到iOS多线程,一般都会谈到四种方式:pthread、N...

  • GCD深入理解学习笔记

    GCD 深入理解第一部分 GCD 深入理解第二部分 如何使用 NSOperations 和 NSOperation...

  • iOS基础:多线程-深入理解GCD

    前言 本篇文章不会介绍GCD的底层实现!!!本篇文章不会介绍GCD的基本使用!!!本篇文章是我这两天再次理解GCD...

  • GCD

    相关链接GCD使用经验与技巧浅谈

  • GCD的dispatch_get_specific与dispat

    概述 GCD是一个多核编程的解决方案。它主要用于优化应用程序以支持多核处理器。 GCD介绍 要理解GCD的使用就必...

网友评论

      本文标题:GCD的理解与使用

      本文链接:https://www.haomeiwen.com/subject/esvpaftx.html