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")
 }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,193评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,306评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,130评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,110评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,118评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,085评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,007评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,844评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,283评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,508评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,395评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,985评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,630评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,797评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,653评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,553评论 2 352

推荐阅读更多精彩内容