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

推荐阅读更多精彩内容