美文网首页
iOS GCD学习总结(一)

iOS GCD学习总结(一)

作者: 西门吹水Jacky | 来源:发表于2020-06-13 18:11 被阅读0次

    一. GCD 简介

    充分利用多核来处理相关任务,它是一个在线程池模式的基础上执行的并发任务

    二.GCD 任务和队列

    任务:

    就是在GCD里的block,执行任务的方式有两种,『同步』和『异步』。

    同步执行(sync):
    不具备开起线程的能力,同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行。

    异步执行(async):
    具备开起线程的能力,异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务

    举个例子:需要打电话给小明和小白。
    同步执行:只有一个手机(当前线程),必须等待和小明的同话结束才能打给小白
    异步执行:有两个或者多个手机(多个线程),不必等待,用第二个手机打给小白

    注意:异步执行(async)虽然具有开启新线程的能力,但是并不一定开启新线程

    队列(Dispatch Queue):

    用来存放任务的队列,队列都是先进先出的,新的任务被追加到队列的未尾,读取执行的任务都是从队列的开头取出任务
    例:即将取出任务1执行【任务1,任务2,任务3】添加新任务4追加到队列末尾,【】代表队列

    在 GCD 中有两种队列:『串行队列』 和 『并发队列』。两者的主要区别是:执行顺序不同,以及开启线程数不同。
    『串行队列(Serial Dispatch Queue)』:一个任务执行完成才能执行下一个任务
    『并发队列(Serial Dispatch Queue)』:多个任务可以同时执行(该能力只在并发队列异步执行下才有)

    三.GCD 使用

    1.创建队列(串行或并发队列)
    2.将任务添加到队列中(同步或异步),然后系统会自动执行队列中的任务

    3.1 队列创建和系统已有的队列获取
        //串行队列 
        let syncQueue:DispatchQueue = DispatchQueue.init(label: "SYNC_QUEUE")//默认串行队列
        //并发队列
        let asyncQqueue:DispatchQueue = DispatchQueue.init(label: "ASYNC_QUEUE", attributes: .concurrent)
        //主队列:实质上就是一个普通的串行队列,当前编写的代码都会放在主线程上执行
        let mainQueue:DispatchQueue = DispatchQueue.main
       //全局并发队列:实质上就是一个普通的并发队列
        let globalQueue:DispatchQueue = DispatchQueue.global()
    
    3.2任务创建

    queue取决于上面四种队列

            //同步执行任务的创建
            queue.sync {
                //任务的具体实现
            }
            //异步执行任务的创建
            queue.async {
                //任务的具体实现
            }
    

    四种队列和两种任务执行方式的不同组合如下:

    同步+串行队列
    异步+串行队列
    同步+并发队列
    异步+并发队列
    同步+主队列
    异步+主队列
    同步+全局队列
    异步+全局队列

    区别如下: 区别图.png

    注意:不能在该串行队列中同步添加任务到该串行队列,否则会造成死锁,

        func deadLock(){
            /****** 在该串行队列中同步添加任务到该串行队列才会造成死锁  ******/
            DispatchQueue.main.sync {//死锁
                print("任务1")
            }
        }
    
        func deadLock(){
            /****** 在该串行队列中同步添加任务到该串行队列才会造成死锁  ******/
            queueSync.sync {
                print("任务1")
                self.queueSync.sync {//死锁
                    print("任务2")
                }
                print("end")
            }
        }
    
    

    死锁原因:串行队列中追加的同步任务1,当同步任务1正执行时,添加同步任务2,此时需要等待任务1执行完毕才能执行任务2,而任务1执行完毕需要等待任务2执行完毕,相互等待,最终死锁,主队列也是如此,死锁这种情况多见于同一个串行队列的嵌套使用。

    以下是几种不同组合的例子:

    同步异步+串行队列
        /**
        * 同步执行 + 串行队列
        * 特点:在当前线程中执行任务,不会开启新线程,执行完一个任务,再执行下一个任务。
        */
        func syncSerial(){
            print("currentThread---\(Thread.current)")
            print("begin")
            let queue:DispatchQueue = DispatchQueue.init(label: "syncSerial")
            queue.sync {
                sleep(4)
                print("1---\(Thread.current)")
            }
            
            queue.sync {
                sleep(2)
                print("2---\(Thread.current)")
            }
            
            queue.sync {
                print("3---\(Thread.current)")
            }
            
            print("end")
        }
    
    输出:currentThread---<NSThread: 0x170071c80>{number = 1, name = main}
    begin
    1---<NSThread: 0x170071c80>{number = 1, name = main}
    2---<NSThread: 0x170071c80>{number = 1, name = main}
    3---<NSThread: 0x170071c80>{number = 1, name = main}
    end
    

    同步(sync)执行任务不具有开启线程的能力,所以共用一个主线程,一个任务执行完毕才能执行下一个任务

        /**
        * 异步执行 + 串行队列
        * 特点:开启一条新线程,执行完一个任务,再执行下一个任务,主线程不再等待
        */
        func asyncSerial(){
            print("currentThread---\(Thread.current)")
            print("begin")
            let queue:DispatchQueue = DispatchQueue.init(label: "asyncSerial")
            queue.async {
                sleep(4)
                print("1---\(Thread.current)")
            }
            
            queue.async {
                sleep(2)
                print("2---\(Thread.current)")
            }
            
            queue.async {
                print("3---\(Thread.current)")
            }
            
            print("end")
        }
    
    currentThread---<NSThread: 0x174074880>{number = 1, name = main}
    begin
    end
    1---<NSThread: 0x1702684c0>{number = 3, name = (null)}
    2---<NSThread: 0x1702684c0>{number = 3, name = (null)}
    3---<NSThread: 0x1702684c0>{number = 3, name = (null)}
    

    异步(async)执行任务具有开启新线程的能力,且主线程不等待输出end,但串行队列只开启一条线程,且任务一个执行完毕才能执行下一个

    同步异步+并发队列
        /**
        * 同步执行 + 并发队列
        * 特点:在当前线程中执行任务,不会开启新线程,执行完一个任务,再执行下一个任务。
        */
        func syncConcurrent(){
            print("currentThread---\(Thread.current)")
            print("begin")
            let queue:DispatchQueue = DispatchQueue.init(label: "syncConcurrent", attributes: .concurrent)
            queue.sync {
                sleep(4)
                print("1---\(Thread.current)")
            }
            
            queue.sync {
                sleep(2)
                print("2---\(Thread.current)")
            }
            
            queue.sync {
                print("3---\(Thread.current)")
            }
            
            print("end")
        }
    
    >输出:
    >currentThread---<NSThread: 0x1700730c0>{number = 1, name = main}
    >begin
    >1---<NSThread: 0x1700730c0>{number = 1, name = main}
    >2---<NSThread: 0x1700730c0>{number = 1, name = main}
    >3---<NSThread: 0x1700730c0>{number = 1, name = main}
    >end
    

    同步(sync)执行任务不具有开启线程的能力,并发列队只在异步(async)执行任务的时候才会开启新的线程且并发执行任务,所以当前共用一个线程(主线程),同步(sync)执行任务需要一个执行完毕才能执行下一个

        /**
        * 异步执行 + 并发队列
        * 特点:队列开启新线程执行任务,主线程不再等待
        */
        func asyncConcurrent(){
            print("asyncConcurrent---\(Thread.current)")
            print("begin")
            let aqueue:DispatchQueue = DispatchQueue.init(label: "asyncConcurrent", attributes: .concurrent)
            aqueue.async {
                sleep(3)
                print("1---\(Thread.current)")
            }
            
            aqueue.async {
                sleep(2)
                print("2---\(Thread.current)")
            }
            
            aqueue.async {
                sleep(1)
                print("3---\(Thread.current)")
            }
            
            print("end")
        }
    
    >输出:asyncConcurrent---<NSThread: 0x17006f740>{number = 1, name = main}
    >begin
    >end
    >3---<NSThread: 0x170263840>{number = 3, name = (null)}
    >2---<NSThread: 0x170263ac0>{number = 4, name = (null)}
    >1---<NSThread: 0x170263b80>{number = 5, name = (null)}
    

    异步(async)执行任务具有开启线程能力,所以当前主线程不等待继续执行下面代码输出end,并发队列开启新的线程并在该线程中执行任务

    同步异步+主队列
        /**
        * 同步执行 + 主队列
        * 特点:死锁
        */
        func syncMain(){
            print("syncMain---\(Thread.current)")
            print("begin")
            DispatchQueue.main.sync {
                //任务1
                print("1---\(Thread.current)")
            }
            print(" end")
        }
    
    syncMain---<NSThread: 0x17006dec0>{number = 1, name = main}
    begin
    (lldb) 
    

    主队列是一个串行队列。这里是因为当系统执行syncMain方法,相当于把syncMain任务放到主队列里,而执行syncMain的过程中添加了任务1到主队列中,syncMain执行完毕需要待任务1执行完,任务1执行完需要等待syncMain执行完,互相等待,所以死锁

        /**
        * 异步执行 + 主队列
        * 特点:在当前线程中执行任务,不会开启新线程,执行完一个任务,再执行下一个任务。
        */
        func asyncMain(){
            print("asyncMain---\(Thread.current)")
            print("begin")
            let aqueue:DispatchQueue = DispatchQueue.main
            aqueue.async {
                sleep(3)
                print("1---\(Thread.current)")
            }
            
            aqueue.async {
                sleep(2)
                print("2---\(Thread.current)")
            }
            
            aqueue.async {
                sleep(1)
                print("3---\(Thread.current)")
            }
            
            print("end")
        }
    
    asyncMain---<NSThread: 0x174067300>{number = 1, name = main}
    begin
    end
    1---<NSThread: 0x174067300>{number = 1, name = main}
    2---<NSThread: 0x174067300>{number = 1, name = main}
    3---<NSThread: 0x174067300>{number = 1, name = main}
    

    异步执行不会做任何等待,可以继续执行任务,虽然异步执行可以开启新的线程,但主队列是串行队列本身已存在主线程,所以此处不再开启新的线程。

    全局并发队列跟普通并发队列并无区别

    相关简书:
    iOS GCD学习总结(二)
    iOS 线程同步方案学习总结
    信号量semaphore学习总结
    iOS dispatch_barrier_sync实现多读单写
    NSOperation和NSOperationQueue学习总结

    相关文章

      网友评论

          本文标题:iOS GCD学习总结(一)

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