iOS GCD學(xué)習(xí)總結(jié)(一)

一. GCD 簡介

充分利用多核來處理相關(guān)任務(wù),它是一個(gè)在線程池模式的基礎(chǔ)上執(zhí)行的并發(fā)任務(wù)

二.GCD 任務(wù)和隊(duì)列

任務(wù):

就是在GCD里的block,執(zhí)行任務(wù)的方式有兩種,『同步』和『異步』。

同步執(zhí)行(sync):
不具備開起線程的能力,同步添加任務(wù)到指定的隊(duì)列中,在添加的任務(wù)執(zhí)行結(jié)束之前,會(huì)一直等待,直到隊(duì)列里面的任務(wù)完成之后再繼續(xù)執(zhí)行。

異步執(zhí)行(async):
具備開起線程的能力,異步添加任務(wù)到指定的隊(duì)列中,它不會(huì)做任何等待,可以繼續(xù)執(zhí)行任務(wù)

舉個(gè)例子:需要打電話給小明和小白。
同步執(zhí)行:只有一個(gè)手機(jī)(當(dāng)前線程),必須等待和小明的同話結(jié)束才能打給小白
異步執(zhí)行:有兩個(gè)或者多個(gè)手機(jī)(多個(gè)線程),不必等待,用第二個(gè)手機(jī)打給小白

注意:異步執(zhí)行(async)雖然具有開啟新線程的能力,但是并不一定開啟新線程

隊(duì)列(Dispatch Queue):

用來存放任務(wù)的隊(duì)列,隊(duì)列都是先進(jìn)先出的,新的任務(wù)被追加到隊(duì)列的未尾,讀取執(zhí)行的任務(wù)都是從隊(duì)列的開頭取出任務(wù)
例:即將取出任務(wù)1執(zhí)行【任務(wù)1,任務(wù)2,任務(wù)3】添加新任務(wù)4追加到隊(duì)列末尾,【】代表隊(duì)列

在 GCD 中有兩種隊(duì)列:『串行隊(duì)列』 和 『并發(fā)隊(duì)列』。兩者的主要區(qū)別是:執(zhí)行順序不同,以及開啟線程數(shù)不同。
『串行隊(duì)列(Serial Dispatch Queue)』:一個(gè)任務(wù)執(zhí)行完成才能執(zhí)行下一個(gè)任務(wù)
『并發(fā)隊(duì)列(Serial Dispatch Queue)』:多個(gè)任務(wù)可以同時(shí)執(zhí)行(該能力只在并發(fā)隊(duì)列異步執(zhí)行下才有)

三.GCD 使用

1.創(chuàng)建隊(duì)列(串行或并發(fā)隊(duì)列)
2.將任務(wù)添加到隊(duì)列中(同步或異步),然后系統(tǒng)會(huì)自動(dòng)執(zhí)行隊(duì)列中的任務(wù)

3.1 隊(duì)列創(chuàng)建和系統(tǒng)已有的隊(duì)列獲取
    //串行隊(duì)列 
    let syncQueue:DispatchQueue = DispatchQueue.init(label: "SYNC_QUEUE")//默認(rèn)串行隊(duì)列
    //并發(fā)隊(duì)列
    let asyncQqueue:DispatchQueue = DispatchQueue.init(label: "ASYNC_QUEUE", attributes: .concurrent)
    //主隊(duì)列:實(shí)質(zhì)上就是一個(gè)普通的串行隊(duì)列,當(dāng)前編寫的代碼都會(huì)放在主線程上執(zhí)行
    let mainQueue:DispatchQueue = DispatchQueue.main
   //全局并發(fā)隊(duì)列:實(shí)質(zhì)上就是一個(gè)普通的并發(fā)隊(duì)列
    let globalQueue:DispatchQueue = DispatchQueue.global()
3.2任務(wù)創(chuàng)建

queue取決于上面四種隊(duì)列

        //同步執(zhí)行任務(wù)的創(chuàng)建
        queue.sync {
            //任務(wù)的具體實(shí)現(xiàn)
        }
        //異步執(zhí)行任務(wù)的創(chuàng)建
        queue.async {
            //任務(wù)的具體實(shí)現(xiàn)
        }

四種隊(duì)列和兩種任務(wù)執(zhí)行方式的不同組合如下:

同步+串行隊(duì)列
異步+串行隊(duì)列
同步+并發(fā)隊(duì)列
異步+并發(fā)隊(duì)列
同步+主隊(duì)列
異步+主隊(duì)列
同步+全局隊(duì)列
異步+全局隊(duì)列

區(qū)別如下:
區(qū)別圖.png

注意:不能在該串行隊(duì)列中同步添加任務(wù)到該串行隊(duì)列,否則會(huì)造成死鎖,

    func deadLock(){
        /****** 在該串行隊(duì)列中同步添加任務(wù)到該串行隊(duì)列才會(huì)造成死鎖  ******/
        DispatchQueue.main.sync {//死鎖
            print("任務(wù)1")
        }
    }

    func deadLock(){
        /****** 在該串行隊(duì)列中同步添加任務(wù)到該串行隊(duì)列才會(huì)造成死鎖  ******/
        queueSync.sync {
            print("任務(wù)1")
            self.queueSync.sync {//死鎖
                print("任務(wù)2")
            }
            print("end")
        }
    }

死鎖原因:串行隊(duì)列中追加的同步任務(wù)1,當(dāng)同步任務(wù)1正執(zhí)行時(shí),添加同步任務(wù)2,此時(shí)需要等待任務(wù)1執(zhí)行完畢才能執(zhí)行任務(wù)2,而任務(wù)1執(zhí)行完畢需要等待任務(wù)2執(zhí)行完畢,相互等待,最終死鎖,主隊(duì)列也是如此,死鎖這種情況多見于同一個(gè)串行隊(duì)列的嵌套使用。

以下是幾種不同組合的例子:

同步異步+串行隊(duì)列
    /**
    * 同步執(zhí)行 + 串行隊(duì)列
    * 特點(diǎn):在當(dāng)前線程中執(zhí)行任務(wù),不會(huì)開啟新線程,執(zhí)行完一個(gè)任務(wù),再執(zhí)行下一個(gè)任務(wù)。
    */
    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)執(zhí)行任務(wù)不具有開啟線程的能力,所以共用一個(gè)主線程,一個(gè)任務(wù)執(zhí)行完畢才能執(zhí)行下一個(gè)任務(wù)

    /**
    * 異步執(zhí)行 + 串行隊(duì)列
    * 特點(diǎn):開啟一條新線程,執(zhí)行完一個(gè)任務(wù),再執(zhí)行下一個(gè)任務(wù),主線程不再等待
    */
    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)執(zhí)行任務(wù)具有開啟新線程的能力,且主線程不等待輸出end,但串行隊(duì)列只開啟一條線程,且任務(wù)一個(gè)執(zhí)行完畢才能執(zhí)行下一個(gè)

同步異步+并發(fā)隊(duì)列
    /**
    * 同步執(zhí)行 + 并發(fā)隊(duì)列
    * 特點(diǎn):在當(dāng)前線程中執(zhí)行任務(wù),不會(huì)開啟新線程,執(zhí)行完一個(gè)任務(wù),再執(zhí)行下一個(gè)任務(wù)。
    */
    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)執(zhí)行任務(wù)不具有開啟線程的能力,并發(fā)列隊(duì)只在異步(async)執(zhí)行任務(wù)的時(shí)候才會(huì)開啟新的線程且并發(fā)執(zhí)行任務(wù),所以當(dāng)前共用一個(gè)線程(主線程),同步(sync)執(zhí)行任務(wù)需要一個(gè)執(zhí)行完畢才能執(zhí)行下一個(gè)

    /**
    * 異步執(zhí)行 + 并發(fā)隊(duì)列
    * 特點(diǎn):隊(duì)列開啟新線程執(zhí)行任務(wù),主線程不再等待
    */
    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)執(zhí)行任務(wù)具有開啟線程能力,所以當(dāng)前主線程不等待繼續(xù)執(zhí)行下面代碼輸出end,并發(fā)隊(duì)列開啟新的線程并在該線程中執(zhí)行任務(wù)

同步異步+主隊(duì)列
    /**
    * 同步執(zhí)行 + 主隊(duì)列
    * 特點(diǎn):死鎖
    */
    func syncMain(){
        print("syncMain---\(Thread.current)")
        print("begin")
        DispatchQueue.main.sync {
            //任務(wù)1
            print("1---\(Thread.current)")
        }
        print(" end")
    }
syncMain---<NSThread: 0x17006dec0>{number = 1, name = main}
begin
(lldb) 

主隊(duì)列是一個(gè)串行隊(duì)列。這里是因?yàn)楫?dāng)系統(tǒng)執(zhí)行syncMain方法,相當(dāng)于把syncMain任務(wù)放到主隊(duì)列里,而執(zhí)行syncMain的過程中添加了任務(wù)1到主隊(duì)列中,syncMain執(zhí)行完畢需要待任務(wù)1執(zhí)行完,任務(wù)1執(zhí)行完需要等待syncMain執(zhí)行完,互相等待,所以死鎖

    /**
    * 異步執(zhí)行 + 主隊(duì)列
    * 特點(diǎn):在當(dāng)前線程中執(zhí)行任務(wù),不會(huì)開啟新線程,執(zhí)行完一個(gè)任務(wù),再執(zhí)行下一個(gè)任務(wù)。
    */
    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}

異步執(zhí)行不會(huì)做任何等待,可以繼續(xù)執(zhí)行任務(wù),雖然異步執(zhí)行可以開啟新的線程,但主隊(duì)列是串行隊(duì)列本身已存在主線程,所以此處不再開啟新的線程。

全局并發(fā)隊(duì)列跟普通并發(fā)隊(duì)列并無區(qū)別

相關(guān)簡書:
iOS GCD學(xué)習(xí)總結(jié)(二)
iOS 線程同步方案學(xué)習(xí)總結(jié)
信號(hào)量semaphore學(xué)習(xí)總結(jié)
iOS dispatch_barrier_sync實(shí)現(xiàn)多讀單寫
NSOperation和NSOperationQueue學(xué)習(xí)總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容