同步与异步、串行与并发(转)

说到多线程,我们必须明白两个概念:线程与队列。我把线程理解为车间的流水线,而队列则决定了每条流水线的工作方式。我们可以往队列中加入任务,并决定该队列在什么线程执行。

主队列异步执行

 DispatchQueue.main.async {
        print(Thread.current)
        DispatchQueue.main.async {
            print(Thread.current)
            sleep(2)
            print(1)
        }
        print(2)
        DispatchQueue.main.async {
            print(Thread.current)
            print(3)
        }
        sleep(1)
    }
  • 打印结果:

主队列异步执行.png
  • 分析:上述代码看似异步执行开了子线程,实则不然,DispatchQueue.main.async实际上队列中的任务还是在主线程执行,也就是同步执行。而它与DispatchQueue.main.sync的区别就是它不会造成死锁。
    由于主队列是串行队列,根据先进先出的原则,上述代码的执行顺序是:将sleep(2)print(1)加入队列->print(2)->将print(3)加入队列->sleep(1)->sleep(2)->print(1)->print(3)

串行队列异步执行

 let serialQueue = DispatchQueue(label: "serial_queue")
    serialQueue.async {
        print(Thread.current)
        serialQueue.async {
            sleep(2)
            print(Thread.current)
            print(1)
        }
        print(2)
        serialQueue.async {
            print(3)
            print(Thread.current)
        }
        sleep(1)
    }
  • 打印结果:


    串行队列异步执行.png
  • 分析:为什么要自定义串行队列与主队列分开来?我们知道主队列就是一个串行队列,而它与普通串行队列在异步执行时有什么区别呢?我们可以尝试打印各个线程中的Thread.current,从结果可以看出,自定义串行队列在异步执行时是创建了支线程的,且因为串行的原因只会创建一个支线程。
    同是串行队列,它的执行顺序同上。

并发队列异步执行

let concurrentQueue = DispatchQueue(label: "concurrent_quque", attributes: .concurrent)
    concurrentQueue.async {
        print(Thread.current)
        concurrentQueue.async {
            print(Thread.current)
            sleep(2)
            print(1)
            print(4)
            print(5)
            print(6)
            print(7)
        }
        print(2)
        concurrentQueue.async {
            print(Thread.current)
            print(3)
        }
        sleep(1)
    }
  • 打印结果:

并发队列异步执行.png
  • 分析:从结果可以看出,并发队列异步执行会开多个线程,其数量等于concurrentQueue.async的调用次数。
    并发队列的特点是它在异步执行时,队列中的任务可以无限接近同时执行。那么问题来了:经过试验,无论我打印多少次,这两段代码都没有体现出并发执行的特性,因为它打结果并没有发生改变。

    image.png

    再观察一下代码,可以发现:第一段异步执行代码中sleep(2)让线程睡了2s,我们把它注释。

    image.png

    多打印几次:

    image.png


    image.png

    因为print(Thread.current)也算一个任务,我们注释掉。

    image.png


    image.png

结论:

  • 对于主队列,同步、异步执行都不会开线程;
  • 对于主队列以外的队列,同步执行不会开线程,异步执行会开线程;
  • 一般来说,开线程的数量取决于.async的调用次数;
  • 无论是串行还是并发,队列中的任务在一个async{ }中都是顺序执行的;
  • 任务并发是指并发队列在异步执行时多个async{ }中的任务无限接近同时执行。
  • 串行队列异步只会创建一个子线程

链接:http://www.jianshu.com/p/b9e02ab5b3a4

原文地址:https://www.cnblogs.com/6duxz/p/7444773.html