GCD - 遐想 in swift3

遐想

即胡思乱想,编程从来都是向前看,所以不考虑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{number = 1, name = main}
1000{number = 1, name = main}
it is main{number = 1, name = main}

串行队列,异步

 @IBAction func action1(_ sender: Any) {
        for i in 1...1000{
            serialQueue.async {
                print("\(i)\(Thread.current)")
            }
        }
    }
第一次点击:
999{number = 3, name = (null)}
1000{number = 3, name = (null)}
第二次点击:
999{number = 4, name = (null)}
1000{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{number = 1, name = main}
1000{number = 1, name = main}
it is main{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{number = 11, name = (null)}
114{number = 13, name = (null)}
it is main{number = 1, name = main}
115{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:{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)")
输出:
顺利执行等待前:{number = 1, name = main}
串行队列1:{number = 3, name = (null)}
串行队列2:{number = 3, name = (null)}
并行队列1:{number = 4, name = (null)}
.
.
.
并行队列100:{number = 44, name = (null)}
.
.
.
串行队列100:{number = 3, name = (null)}
顺利执行等待后:{number = 1, name = main}
执行完成2:{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:这里绝对的并发:{number = 40, name = (null)}
49:这里绝对的并发:{number = 30, name = (null)}
当前只会有一个线程在服务:{number = 30, name = (null)}
51:这里绝对的并发:{number = 40, name = (null)}
52:这里绝对的并发:{number = 30, name = (null)}
//当然这里不一定是这么个顺序:48、49、同步任务、51、52。
//但一定是先执行了前面50个任务,然后等待`同步点`执行,再执行后面49个任务。

你可能感兴趣的:(GCD - 遐想 in swift3)