美文网首页
GCD - 遐想 in swift3

GCD - 遐想 in swift3

作者: 离子来了 | 来源:发表于2016-04-19 21:16 被阅读78次

    遐想

    即胡思乱想,编程从来都是向前看,所以不考虑switf3以前

    同步

    阻塞当前线程

    异步

    不阻塞当前线程

    warning:

    1.不能用同步和异步是否能开启线程来区别,跟是否具有开启线程的能力没有半毛钱关系

    下面是2种线程阻塞的场景(串行队列强行同步执行)

      override func viewDidLoad() {
            super.viewDidLoad()
            DispatchQueue.main.sync {
                print("这里会阻塞死亡,永远都不会执行")
            }  //主队列是串行队列,里面任务是依次执行。
              //这里开辟一个同步任务,执行这个任务就要先把前面的任务执行完毕。
              //但是同步任务需要立刻执行,就会造成阻塞。
        }
    
    serialQueue.async {//serialQueue串行队列,这里不管同步(sync)还是异步(async)效果都一样
         print("\(1)\(Thread.current)")
         self.serialQueue.sync {
               print("it is main\(Thread.current)
             }
       } //阻塞现象同上
    

    GCD

    遐想:GCD内部应该维持着一个线程池子(线程的多少得益于程序运行环境)。
    还维护着多种队列:
    1.主队列

    DispatchQueue.main//获取主队列,串行队列
    

    2.全局队列,都是并行队列Qos(quality of service)

    public enum QoSClass {
            case background //后台
            case utility     //周期性的用户请求,比如:定时检查新消息
            case `default`  //这个看似这么特殊的默认,最好不用,默认就用默认参数吧
            case userInitiated //用户期望(用于请求的任务,不太耗时的操作)
            case userInteractive //用户交互(与图形处理相关的任务,比如动画)
            case unspecified //意思是未说明的,那就不用吧
        }
    //获取全局队列
    let globleQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.background)
    

    3.自定义队列

    let serialQueue     = DispatchQueue(label: "serialQueue") //串行队列 
    let concurrentQueue = DispatchQueue(label: "concurrentQueue", attributes: DispatchQueue.Attributes.concurrent) //并行队列
    

    GCD对队列的维护:
    1.只要队列中有任务,GCD就会从线程池中调度线程来执行
    2.主队列,只会调度主线程来执行(主线程和主队列2个是绑定的)
    3.其他队列,会调度其他线程来处理任务

    同步 异步
    串行队列 当前线程,一个一个执行 任意线程,一个一个执行
    并行队列 当前线程,一个一个执行 多个线程,同时执行

    warning:

    遐想:上面表格的现象,只是实践后的总结,理论上:任何任务都不能确定是在那个线程上执行的。
    线程切换是要消耗一定的资源的,居于这个考虑,以下推断
    a. 串行队列:已经决定任务的执行顺序,所以串行队列不管同步还是异步都只需要调度一个线程就可以了.
    同步:GCD不想浪费线程切换的资源,就直接使用当前线程
    异步:GCD会从线程池里面随便调度一个线程来执行这个队列的任务,执行完队列的全部任务,就会放回线程池,等待调度
    b. 并行队列:里面的任务没有执行顺序
    同步:GCD不想浪费线程切换的资源,就直接使用当前线程
    异步:GCD会根据当前系统资源最优化的调度不定数(>=0,理论上没有可调度的线程的时候只有等待了)的线程来处理任务

    串行队列,同步

    @IBAction func action1(_ sender: Any) {
            for i in 1...1000{
                serialQueue.sync {
                    print("\(i)\(Thread.current)")
                }
            }
            print("it is main\(Thread.current)")
        }
    999<NSThread: 0x170074f80>{number = 1, name = main}
    1000<NSThread: 0x170074f80>{number = 1, name = main}
    it is main<NSThread: 0x170074f80>{number = 1, name = main}
    

    串行队列,异步

     @IBAction func action1(_ sender: Any) {
            for i in 1...1000{
                serialQueue.async {
                    print("\(i)\(Thread.current)")
                }
            }
        }
    第一次点击:
    999<NSThread: 0x174068840>{number = 3, name = (null)}
    1000<NSThread: 0x174068840>{number = 3, name = (null)}
    第二次点击:
    999<NSThread: 0x174072980>{number = 4, name = (null)}
    1000<NSThread: 0x174072980>{number = 4, name = (null)}
    //每次调度的都是不同的线程来执行,但是不保证一定不是。一切都是资源优化来调度的
    

    并行队列,同步

     @IBAction func action1(_ sender: Any) {
            for i in 1...1000{
                concurrentQueue.sync {
                    print("\(i)\(Thread.current)")
                }
            }
            print("it is main\(Thread.current)")
        }
    999<NSThread: 0x170264880>{number = 1, name = main}
    1000<NSThread: 0x170264880>{number = 1, name = main}
    it is main<NSThread: 0x170264880>{number = 1, name = main}
    

    并行队列,异步

     @IBAction func action1(_ sender: Any) {
            for i in 1...1000{
                concurrentQueue.async {
                    print("\(i)\(Thread.current)")
                }
            }
            print("it is main\(Thread.current)")
        }
    113<NSThread: 0x17426d680>{number = 11, name = (null)}
    114<NSThread: 0x17426e700>{number = 13, name = (null)}
    it is main<NSThread: 0x17007f380>{number = 1, name = main}
    115<NSThread: 0x17426e700>{number = 13, name = (null)}
    

    遐想:串行队列,不管同步异步,每次(每次,指的是:串行队列中任务的一次执行,一次执行是将里面的任务执行完毕。当加入新任务后,算下一次了,GCD将另外从线程池里调度,调度规则还是同步就是当前线程,异步就是随便调度一个线程)都只有一个线程为其服务。同步就是当前线程,异步就是从调度池里随便调度一个

    异步并行队列

    这情况就不说了,简直乱执行嘛(这就是想要的结果)

    延迟执行

     DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2){
                
                //do something
            
            }
    

    DispatchWorkItem

    将上面的block封装成一个taskid

    let taskID = DispatchWorkItem {
         print("workItem is working:\(Thread.current)"
    }
    concurrentQueue.async(execute: taskID)//将任务放入队列
    item.wait()//等待,等任务执行完成才继续后面的行为
    item.wait(timeout: DispatchTime.now() + 4) //最多等待多少秒,就继续执行下面的行为
    item.cancel() //在任务还未执行之前,可以取消该任务
    item.perform() //直接在当前线程执行block里面的任务,不会触发notify监听
    item.notify(queue: serialQueue){ //和队列组一样的通知,多次测试,执行这个通知的线程和执行任务的线程是一致的()
         print("workitem haved doing:\(Thread.current)")
    }
    

    使用

    let item = DispatchWorkItem {
         print("workItem is working:\(Thread.current)")
    }
    serialQueue.async { 
        sleep(5)
        print("sleep 5")
    }
    serialQueue.async(execute: item)
    print("before working")
    item.cancel() 
    item.wait()//等待
    item.notify(queue: serialQueue){
    print("workitem haved doing:\(Thread.current)")
    }
    print("after working")
    输出:
    before working
    sleep 5
    after working
    workitem haved doing:<NSThread: 0x1702721c0>{number = 3, name = (null)}
    

    mark:item.cancel()并不能影响到item.wait()item.notify()

    队列组

    将一堆任务化为一个组,并可以对组进行完成监听,或者阻塞,完成后在继续执行,

    let dispatchGroup   = DispatchGroup()
    dispatchGroup.notify(queue: concurrentQueue){}//需要放在最后,否则会有问题(按照这个怪咧来就是)
    
    for i in 1...100{
        serialQueue.async(group: dispatchGroup){
              print("串行队列\(i):\(Thread.current)")
        }
    }
    for i in 1...100{
        concurrentQueue.async(group: dispatchGroup){
             print("并行队列\(i):\(Thread.current)")
        }
    }
    dispatchGroup.notify(queue: concurrentQueue){//队列组任务结束,会收到通知
         print("执行完成2:\(Thread.current)")
     }
    print("顺利执行等待前:\(Thread.current)")
    dispatchGroup.wait()//阻塞后面代码的执行,直到队列组任务的完成
    print("顺利执行等待后:\(Thread.current)")
    输出:
    顺利执行等待前:<NSThread: 0x170072f80>{number = 1, name = main}
    串行队列1:<NSThread: 0x17026e640>{number = 3, name = (null)}
    串行队列2:<NSThread: 0x17026e640>{number = 3, name = (null)}
    并行队列1:<NSThread: 0x17026e700>{number = 4, name = (null)}
    .
    .
    .
    并行队列100:<NSThread: 0x17407df80>{number = 44, name = (null)}
    .
    .
    .
    串行队列100:<NSThread: 0x17026e640>{number = 3, name = (null)}
    顺利执行等待后:<NSThread: 0x170072f80>{number = 1, name = main}
    执行完成2:<NSThread: 0x17407df80>{number = 44, name = (null)}
    

    信号量

    遐想:最主要的就是用于对资源上锁。当信号设置为1的话

    let semaphore = DispatchSemaphore(value: 1)
    semaphore.wait() //-1
    semaphore.signal() //+1
    

    Dispatch Barrier(栅栏)

    只针对一个并行队列
    同步点之前的任务,会并发执行,到了同步点就会等待,等待同步点的任务执行完成的时候,继续后面的任务,再次并发执行

      let writeTask = DispatchWorkItem(flags: DispatchWorkItemFlags.barrier) { //同步点
      print("当前只会有一个线程在服务:\(Thread.current)")
    }
     for i in 0..<100 {
           if i == 50 {
                 concurrentQueue.async(execute: writeTask)
            }else{
                  let readTask = DispatchWorkItem {
                   print("\(i):这里绝对的并发:\(Thread.current)")
                  }
                   concurrentQueue.async(execute: readTask)
               }  
           }
        }
    输出:
    48:这里绝对的并发:<NSThread: 0x17426b040>{number = 40, name = (null)}
    49:这里绝对的并发:<NSThread: 0x17026a840>{number = 30, name = (null)}
    当前只会有一个线程在服务:<NSThread: 0x17026a840>{number = 30, name = (null)}
    51:这里绝对的并发:<NSThread: 0x17426b040>{number = 40, name = (null)}
    52:这里绝对的并发:<NSThread: 0x17026a840>{number = 30, name = (null)}
    //当然这里不一定是这么个顺序:48、49、同步任务、51、52。
    //但一定是先执行了前面50个任务,然后等待`同步点`执行,再执行后面49个任务。
    

    相关文章

      网友评论

          本文标题:GCD - 遐想 in swift3

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