iOS多线程-GCD(Swift)

GCD准确的来讲应该叫做并发编程技术,因为swift3.0后GCD使用方式有很大的变化这里用Swift来重新整理一下GCD。

开发中常见代码

  • 同步执行方法,这句话不执行完,就不会执行下一个任务。同步执行不会开启线程。

    DispatchQueue.global().sync {
          print(Thread.current)
    }
    
  • 异步执行任务,任务没有执行完毕,可以不用等待,异步执行下一个任务 ,具备开启线程的能力! 异步通常又是多线程的代名词!

    DispatchQueue.global().async {
           print(Thread.current)
    }
    
  • 开发中最常见的情形,在子线程执行完任务后回到主线程更新UI。

    DispatchQueue.global().async {
           print(Thread.current)
           DispatchQueue.main.async {
              print(Thread.current)
          }
    }
    

GCD核心概念

将任务添加到队列,指定任务执行的方法。

  • 任务
    • OC里面用block 封装,swift是闭包。
    • 就是一个提前准备好的代码块,在需要的时候执行。
  • 队列(负责调度任务)
    • 串行队列: 一个接一个的调度任务
    • 并发队列: 可以同时调度多个任务
  • 任务执行函数(任务都需要在线程中执行!!)
    • 同步执行: 不会到线程池里面去获取子线程!
    • 异步执行: 只要有任务,会去线程池取子线程(主队列除外)
  • Demo
    • 串行队列,同步任务
      //创建串行队列
      let serialQueue = DispatchQueue(label: "SCGCD", attributes: .init(rawValue: 0))
      //同步执行
      for i in 0..<10 {
         serialQueue.sync {
            print(i)
            print(Thread.current)
         }
      }
      
      执行结果是不会开启子线程,顺序执行。
    • 串行队列,异步任务。
      //创建串行队列
      let serialQueue = DispatchQueue(label: "SCGCD", attributes: .init(rawValue: 0))
      //异步步执行
       for i in 0..<10 {
           serialQueue.async {
               print(i)
               print(Thread.current)
           }
      }
      
      执行结果是会开启子线程,顺序执行。
    • 并发队列,异步执行。
       //创建并发队列
      let conQueue = DispatchQueue(label: "Mazy", attributes: .concurrent)
      //异步执行
       for i in 0..<10 {
          conQueue.async {
             print(i)
             print(Thread.current)
          }
      }
      
      执行结果是会开启子线程,不是顺序执行。
    • 并发队列,同步执行。
      //创建并发队列
      let conQueue = DispatchQueue(label: "KaitoGCD", attributes: .concurrent)
      //同步执行
      for i in 0..<10 {
         conQueue.sync {
             print(i)
             print(Thread.current)
         }
      }
      
      执行结果是不会会开启子线程,顺序执行。
  • 总结
    • 开不开线程,取决于执行任务的函数,同步不开,异步才能开
    • 开几条线程,取决于队列,串行开一条,并发可以开多条(异步)

同步任务

利用同步任务,能够做到任务依赖关系,前一个任务是同步任务,这个任务不执行完,队列就不会调度后面的任务。(应用场景是要等待一个任务执行完再去执行其他的任务)

  • 例子:
    //创建并发队列
    let conQueue = DispatchQueue(label: "KaitoGCD", attributes: .concurrent)
    conQueue.sync {
        print("用户登录\(Thread.current)")
    }
    conQueue.async {
         print("支付\(Thread.current)")
    }
    conQueue.async {
        print("下载\(Thread.current)")
    }
    
    这个代码就会等每次登录操作完成后才是支付和下载。

全局队列

let globalQueue = DispatchQueue.global()
  • 全局队列其实跟并发队列差不多,都是并发,能够调度多个线程。
  • 全局队列与并发队列区别
    • 1 名称,并发队列取名字,适合于企业开发跟踪错误
    • 2 并发队列在MRC情况下需要使用的dispatch_release(q);//ARC 情况下不需要release !

主队列

let globalQueue = DispatchQueue.main
  • 主队列其实和串行队列差不多,都是一个一个的执行任务。
  • 主队列和串行队列的区别
    • 串行队列最多只能开启一条线程,可以是子线程。
    • 主队列主要是负责在主线程上执行任务。
  • 主队列特性:以FIFO调度任务,如果主线程上有任务在执行,主队列就不会调度任务。这种特性可能会造成一种死锁的情况(面试常问):
    • 同步任务死锁:当前是在主线程,让主队列执行同步任务!
      override func viewDidLoad() {
          super.viewDidLoad()
          print(1)
          DispatchQueue.main.sync {
              print(Thread.current)
          }
      }
      
      以上代码便是死锁的情况,程序会崩溃,因为viewDidLoad()里面执行的任务和DispatchQueue.main.sync执行的任务互相等待造成死锁。

延迟执行

//延迟1秒在子线程中异步执行
DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + 1) {
        print(Thread.current)
}

一次执行

Swift3以后原有的Dispatch once已经被废弃了。这里就用OC来写代码例子,在OC用dispatch_once来写单例还是应用的很多的。(ps:Swift写单例真的比OC方便很多)

static dispatch_once_t onceToken;
 NSLog(@"%ld",onceToken);
//苹果推荐使用 gcd 一次执行,效率高
dispatch_once(&onceToken, ^{
    //只会执行一次!!
      NSLog(@"执行了%@",[NSThread currentThread]);
 });

调度组

用一个调度组,可以监听全局队列的任务,主队列去执行最后的任务

//调度组
let group = DispatchGroup()
//添加任务,让队列调度,任务执行情况,最后通知群组
DispatchQueue.global().async(group: group, qos: .default, flags: [], execute: { 
            
       print("下载1")
})
DispatchQueue.global().async(group: group, qos: .default, flags: [], execute: {
            
     print("下载2")
})
DispatchQueue.global().async(group: group, qos: .default, flags: [], execute: {
            
      print("下载3")
 })
//所有任务执行完毕后,通知
 group.notify(queue: DispatchQueue.main) { 
            
      print("回到主队列更新UI")
 }

你可能感兴趣的:(iOS多线程-GCD(Swift))