iOS 多線程【GCD】知識(shí)詳解

多線程


談到多線程,一般都會(huì)有個(gè)疑問:

線程是什么?而談到線程,不可避免的就是會(huì)談到另外一個(gè)詞:進(jìn)程。那么,什么是線程?什么是進(jìn)程?兩者的區(qū)別和聯(lián)系?

  • 進(jìn)程:是系統(tǒng)資源分配和調(diào)度的獨(dú)立單位
  • 線程:我的理解就是線程是CPU調(diào)度和分派的基本單位

舉個(gè)例子:現(xiàn)在有一個(gè)工廠,這個(gè)工廠有三個(gè)車間:車間A,B和C,每個(gè)車間都有4臺(tái)機(jī)器。A負(fù)責(zé)生產(chǎn)鞋帶,B負(fù)責(zé)生產(chǎn)鞋底,C負(fù)責(zé)生產(chǎn)鞋身?,F(xiàn)在我們收到了一批訂單,要生產(chǎn)1000雙鞋。那開始生產(chǎn)的時(shí)候,就是車間為一個(gè)單位,獲取資源開始工作,每個(gè)車間里,又分派給4臺(tái)機(jī)器開始去工作進(jìn)行生產(chǎn)。
在這里,車間就類似我們的進(jìn)程。車間里的線程就是我們的線程。

因此,我們可以知道,一個(gè)進(jìn)程里至少得有一條線程才可以工作。

使用多線程的好處是:可以充分利用CPU的資源進(jìn)行并發(fā)工作


現(xiàn)在來看看iOS里面的多線程

iOS里面使用多線程主要是兩種途徑GCD和NSOpeartionQueue

GCD 是蘋果對(duì)C語言線程的封裝,使用還是利用c語言的函數(shù)來,據(jù)說特點(diǎn)是能夠高效的利用設(shè)備的性能

NSOpeartionQueue 是蘋果對(duì)GCD的封裝,封裝成大家熟悉的對(duì)象,直接用對(duì)象語言去操作

這里我們主要是介紹GCD

要了解GCD,首先需要了解的是四個(gè)概念:同步函數(shù),異步函數(shù),并發(fā)隊(duì)列和串行隊(duì)列

  • 同步函數(shù) dispatch_sync 開頭的函數(shù)。特點(diǎn)是需要這個(gè)函數(shù)的代碼執(zhí)行完畢,后面的代碼才可以進(jìn)行

  • 異步函數(shù) dispatch_async 開頭的函數(shù)。特點(diǎn)是后面的代碼不需要等待這個(gè)函數(shù)的代碼執(zhí)行完畢,可以同時(shí)進(jìn)行

  • 并發(fā)隊(duì)列 隊(duì)列里的任務(wù)可以并發(fā)執(zhí)行

    并發(fā)隊(duì)列的獲取方式有兩種:
    1.通過dispatch_queue_create函數(shù)創(chuàng)建

     dispatch_queue_t   queue = dispatch_queue_create("first_concurrent_queue", DISPATCH_QUEUE_CONCURRENT);
    

    2.通過dispatch_get_global_queue函數(shù)可以獲取系統(tǒng)提供的全局并發(fā)隊(duì)列

    dispatch_queue_t queue = dispatch_get_global_queue(0, 0)

  • 串行隊(duì)列 隊(duì)列里的任務(wù)是一個(gè)接一個(gè)執(zhí)行的

串行隊(duì)列的獲取方式也有兩種:1.通過dispatch_queue_create函數(shù)創(chuàng)建。 2.通過dispatch_get_main_queue函數(shù)可以獲取系統(tǒng)提供的主隊(duì)列

1.通過dispatch_queue_create函數(shù)創(chuàng)建
dispatch_queue_t queue = dispatch_queue_create("first_serial_queue", DISPATCH_QUEUE_DISPATCH_QUEUE_SERIAL);

2.通過dispatch_get_main_queue()函數(shù)可以獲取系統(tǒng)提供的主隊(duì)列
dispatch_queue_t queue = dispatch_get_main_queue()

這個(gè)主隊(duì)列比較重要,也比較特殊。主隊(duì)列里,只有一條主線程,一般情況下,在整個(gè)APP中,大部分的操作都是在這條線程上。UI控件的更新和行為都要在這個(gè)線程上執(zhí)行。因此,它也叫UI線程。

在GCD里,主要是利用這四個(gè)進(jìn)行組合使用,下面我們一個(gè)一個(gè)來看

  • 同步并發(fā)隊(duì)列

    同步并發(fā)

    首先touchesBegan方法是在主線程執(zhí)行的。從輸出可以看到,同步并發(fā)隊(duì)列并不會(huì)創(chuàng)建新的子線程,四個(gè)個(gè)任務(wù)都是順序執(zhí)行的。

  • 同步串行隊(duì)列

    同步串行

    從輸出看,同步串行隊(duì)列也不會(huì)創(chuàng)建新的子線程來執(zhí)行任務(wù),并且四個(gè)任務(wù)也是順序執(zhí)行的

  • 異步并發(fā)隊(duì)列

    異步并發(fā)

    從輸出看,異步并發(fā)隊(duì)列創(chuàng)建了三條線程。因?yàn)槭钱惒綀?zhí)行的緣故,輸出語句按照邏輯上應(yīng)該是無序的。個(gè)人認(rèn)為之所以end這條語句先輸出,是因?yàn)楫惒讲僮鏖_辟線程耗費(fèi)了一點(diǎn)點(diǎn)時(shí)間。如果三個(gè)任務(wù)里執(zhí)行的是耗時(shí)操作,那輸出語句就是看哪個(gè)任務(wù)先執(zhí)行完成。

  • 異步串行隊(duì)列

    異步串行

    從輸出結(jié)果看,異步串行,也創(chuàng)建了一條子線程。三個(gè)任務(wù)都是在這一條子線程上執(zhí)行。邏輯上三個(gè)任務(wù)是有序的。

總結(jié)

隊(duì)列 同步 異步
并發(fā)隊(duì)列 不會(huì)創(chuàng)建子線程,順序執(zhí)行 會(huì)創(chuàng)建多條子線程,任務(wù)之間是并發(fā)執(zhí)行
串行隊(duì)列 不會(huì)創(chuàng)建子線程,順序執(zhí)行 只會(huì)創(chuàng)建一條子線程,子線程上的任務(wù)順序執(zhí)行
主隊(duì)列 不會(huì)創(chuàng)建子線程,順序執(zhí)行 不會(huì)創(chuàng)建子線程,任務(wù)在主線程上順序執(zhí)行

其他函數(shù)

dispatch_group 參考來源

是可以將多個(gè)任務(wù)放在一個(gè)任務(wù)組里,進(jìn)行統(tǒng)一的管理

  • dispatch_group_async(group, queue, block)將block任務(wù)添加到queue隊(duì)列,并被group組管理
  • dispatch_group_enter(group)聲明dispatch_group_enter(group)下面的任務(wù)由group組管理,group組的任務(wù)數(shù)+1
  • dispatch_group_leave(group)相應(yīng)的任務(wù)執(zhí)行完成,group組的任務(wù)數(shù)-1
  • dispatch_group_create()創(chuàng)建一個(gè)group組
  • dispatch_group_wait(group1, DISPATCH_TIME_FOREVER)
    當(dāng)前線程暫停,等待dispatch_group_wait(group1, DISPATCH_TIME_FOREVER)上面的任務(wù)執(zhí)行完成后,線程才繼續(xù)執(zhí)行
  • dispatch_group_notify(group1, queue1,block)
    監(jiān)聽group組中任務(wù)的完成狀態(tài),當(dāng)所有的任務(wù)都執(zhí)行完成后,觸發(fā)block塊,執(zhí)行總結(jié)性處理。

dispatch_group的使用

dispatch_group_async(group,queue,block)dispatch_group_notify(group,queue,block)組合使用。

同步任務(wù)和異步任務(wù)

同步任務(wù)

輸出語句hahahaha會(huì)等上面的所有任務(wù)都完成了,才會(huì)去執(zhí)行。

異步任務(wù)

可以看到,因?yàn)槔锩娴娜蝿?wù)都是異步執(zhí)行的,這個(gè)時(shí)候hahahaha不會(huì)等待上面所有的任務(wù)完成。

dispatch_group_enter(group) dispatch_group_leave(group)dispatch_group_notify(group1, queue1,block) 組合使用

dispatch_group_enter(group)
dispatch_async(queue, ^{
            sleep(3);
            NSLog(@"====second=====%@",[NSThread currentThread]);
        });
dispatch_group_leave(group)

dispatch_group_async(group, queue, ^{
        dispatch_async(queue, ^{
            sleep(3);
            NSLog(@"====second=====%@",[NSThread currentThread]);
        });
    });

作用是一樣的。兩種寫法而已。


柵欄函數(shù) dispatch_barrier_

作用是可以等這個(gè)隊(duì)列里的任務(wù)都完成的時(shí)候做一個(gè)操作。


柵欄異步

柵欄同步

注意:柵欄函數(shù)使用的queue,必須是并行隊(duì)列,并且不能是系統(tǒng)提供的并發(fā)隊(duì)列

dispatch_apply 快速迭代

快速迭代

利用多線程進(jìn)行的快速循環(huán),循環(huán)次數(shù)多的情況下,更加快速。

dispatch_sem 信號(hào)量

信號(hào)量就是一個(gè)資源計(jì)數(shù)器,對(duì)信號(hào)量有兩個(gè)操作來達(dá)到互斥,分別是P和V操作。 一般情況是這樣進(jìn)行臨界訪問或互斥訪問的: 設(shè)信號(hào)量值為1, 當(dāng)一個(gè)進(jìn)程1運(yùn)行是,使用資源,進(jìn)行P操作,即對(duì)信號(hào)量值減1,也就是資源數(shù)少了1個(gè)。這是信號(hào)量值為0。系統(tǒng)中規(guī)定當(dāng)信號(hào)量值為0是,必須等待,知道信號(hào)量值不為零才能繼續(xù)操作。 這時(shí)如果進(jìn)程2想要運(yùn)行,那么也必須進(jìn)行P操作,但是此時(shí)信號(hào)量為0,所以無法減1,即不能P操作,也就阻塞。這樣就到到了進(jìn)程1排他訪問。 當(dāng)進(jìn)程1運(yùn)行結(jié)束后,釋放資源,進(jìn)行V操作。資源數(shù)重新加1,這是信號(hào)量的值變?yōu)?. 這時(shí)進(jìn)程2發(fā)現(xiàn)資源數(shù)不為0,信號(hào)量能進(jìn)行P操作了,立即執(zhí)行P操作。信號(hào)量值又變?yōu)?.次數(shù)進(jìn)程2咱有資源,排他訪問資源。 這就是信號(hào)量來控制互斥的原理

作者:紙簡(jiǎn)書生
鏈接:http://m.itdecent.cn/p/04ca5470f212
來源:簡(jiǎn)書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。

信號(hào)量使用

寫在最后-多線程不好的地方

  • 使用不好,會(huì)造成死鎖問題

    最經(jīng)典的例子:


    死鎖問題

    問題分析:首先touchBegan方法肯定是在主線程執(zhí)行的。然后我們是在方法里面,進(jìn)行了一個(gè)同步的函數(shù)任務(wù),因?yàn)槭峭饺蝿?wù),那么主線程就要等這個(gè)任務(wù)結(jié)束了,才往后面走。但是這個(gè)任務(wù)是會(huì)被主隊(duì)列加到主線程里執(zhí)行,然而這個(gè)時(shí)候主線程里正在執(zhí)行touchBegan這個(gè)任務(wù),只有等這個(gè)任務(wù)結(jié)束了,才能執(zhí)行其他的。因此雙方就都在等待,造成死鎖問題。

    解決方法很簡(jiǎn)單:既然是雙方相互等待造成的問題,那只要讓一方不等就行了。這個(gè)任務(wù)可以執(zhí)行在其他線程就行了或者不使用同步函數(shù),使用異步函數(shù)

  • 多線程使用,肯定會(huì)有線程安全問題(訪問臨界資源)

    這個(gè)就不過多說了,類似的問題很多,比如買票什么的

最后編輯于
?著作權(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),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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