iOS 多線程的一些理解及GCD的深入淺出

為什么要使用多線程:

每一個程序都有一個主線程,用來更新UI,處理用戶交互事件等,所以主線程的流暢度直接決定用戶體驗;因此對于一些耗時操作就需要通過開啟子線程來完成(比如網(wǎng)絡(luò)加載以及大數(shù)據(jù)的讀寫操作等),防止頁面假死,提高運行效率。

對于串行并行,同步異步的理解:

先來說一說隊列與任務(wù),隊列分為串行隊列和并行隊列,任務(wù)分為同步任務(wù)跟異步任務(wù)。這兩兩組合就成為了串行隊列同步執(zhí)行,串行隊列異步執(zhí)行,并行隊列同步執(zhí)行,并行隊列異步執(zhí)行。

串行隊列:任務(wù)按照順序被調(diào)度,前一個任務(wù)不執(zhí)行完畢,隊列不會調(diào)度

并行隊列:只要有空閑的線程,隊列就會調(diào)度當(dāng)前的任務(wù),交給線程去執(zhí)行,不需要考慮前面是否有任務(wù)在執(zhí)行。

主隊列:專門用來在主線程調(diào)度任務(wù)的隊列,所以主隊列的任務(wù)都要在主線程來執(zhí)行,主隊列會隨著程序的啟動一起創(chuàng)建,我們只需get即可

全局隊列:是系統(tǒng)為了方便程序員開發(fā)提供的,其工作表現(xiàn)與并發(fā)隊列一致,那么全局隊列跟并發(fā)隊列的區(qū)別是什么呢?

1.全局隊列:無論ARC還是MRC都不需要考錄釋放,因為系統(tǒng)提供的我們只需要get就可以了

2.并發(fā)隊列:再MRC下,并發(fā)隊列創(chuàng)建出來后,需要手動釋放dispatch_release()

同步執(zhí)行:不會開啟新的線程,任務(wù)按順序執(zhí)行

異步執(zhí)行:會開啟新的線程,任務(wù)可以并發(fā)的執(zhí)行

那么有這么幾種組合

串行隊列同步執(zhí)行:綜合上面闡述的串行隊列的特點 --- 按順序執(zhí)行,同步:不會開啟新的線程,則串行隊列同步執(zhí)行只是按部就班的one by one執(zhí)行,且會阻塞當(dāng)前線程。

串行隊列異步執(zhí)行:雖然隊列中存放的是異步執(zhí)行的任務(wù),會開啟新的線程,但是結(jié)合串行隊列的特點,前一個任務(wù)不執(zhí)行完畢,隊列不會調(diào)度,所以串行隊列異步執(zhí)行也是one by one的執(zhí)行,但不會阻塞當(dāng)前線程。

并行隊列同步執(zhí)行:結(jié)合上面闡述的并行隊列的特點,和同步執(zhí)行的特點,可以明確的分析出來,雖然并行隊列可以不需等待前一個任務(wù)執(zhí)行完畢就可調(diào)度下一個任務(wù),但是任務(wù)同步執(zhí)行不會開啟新的線程,所以任務(wù)也是one by one的執(zhí)行,同樣會阻塞當(dāng)前線程。

并行隊列異步執(zhí)行:在上一條中說明了并行隊列的特點,而異步執(zhí)行的任務(wù)會開啟新的線程,所以這種組合可以實現(xiàn)任務(wù)的并發(fā),且不會阻塞當(dāng)前線程。

隊列的特點:只負(fù)責(zé)任務(wù)的調(diào)度,而不負(fù)責(zé)執(zhí)行任務(wù)的具體內(nèi)容(由線程負(fù)責(zé)執(zhí)行);先進(jìn)先出,按照先后順序去調(diào)度任務(wù)。

開啟方式:

1.NSThread;2.NSOperation;3.GCD


1.GCD隊列的使用:

dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

async表明異步執(zhí)行,block代表的要執(zhí)行的任務(wù),queue則是你把任務(wù)交給誰來處理了.(除了 ? ? async,還有sync,delay).

而系統(tǒng)默認(rèn)就有一個串行隊列main_queue和并行隊列g(shù)lobal_queue,無需創(chuàng)建,直接get就好,此外也可以手動創(chuàng)建隊列:

串行隊列:dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);線程池只提供一個線程用來執(zhí)行任務(wù),所以后一個任務(wù)必須等到前一個任務(wù)執(zhí)行結(jié)束才能開始。

并行隊列:dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);線程池可以提供多個線程來執(zhí)行任務(wù),如果采用異步執(zhí)行任務(wù)則可以按序啟動多個任務(wù)并發(fā)執(zhí)行。

2.dispatch_group_async的使用:

dispatch_group_async可以實現(xiàn)監(jiān)聽一組任務(wù)是否完成,完成后得到通知執(zhí)行其他的操作。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, queue, ^{ /*任務(wù)a */ });

dispatch_group_async(group, queue, ^{ /*任務(wù)b */ });

dispatch_group_async(group, queue, ^{ /*任務(wù)c */ });

dispatch_group_notify(group,dispatch_get_main_queue(), ^{ // 在a、b、c異步執(zhí)行都完成后,會回調(diào)這里});


dispatch_group_wait(group, DISPATCH_TIME_FOREVER); //會根據(jù)group中是否還有任務(wù)在執(zhí)行來阻塞當(dāng)前線程,一般不會放在主線程里面執(zhí)行,否則會造成頁面假死,在子線程中此方法跟dispatch_group_notify有同樣的效果,dispatch_time_t可以自定義,當(dāng)超過這個時間則會自動放開線程,相對來說比dispatch_group_notify更加靈活

如果不通過dispatch_group_async來提交任務(wù),也可以通過?dispatch_group_enter(group) 與 dispatch_group_leave(group) 搭配來提交到group中,比如一般的網(wǎng)絡(luò)請求本身會開啟線程,所以不用通過dispatch_group_async再次開啟線程,使用enter跟leave來提交到group中更好

3.dispatch_barrier_async的使用:

dispatch_barrier_async是在前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行,而且它后面的任務(wù)等它執(zhí)行完成之后才會執(zhí)行

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

dispatch_async(queue, ^{ /*任務(wù)a */ });

dispatch_async(queue, ^{ /*任務(wù)b */ });

dispatch_barrier_async(queue, ^{ /*任務(wù)c */ });

dispatch_async(queue, ^{ /*任務(wù)d */ });

dispatch_async(queue, ^{ /*任務(wù)e */ });

其順序是:開始a和b并發(fā)異步執(zhí)行,等都執(zhí)行完之后,開始執(zhí)行c,c執(zhí)行完之后,再并發(fā)執(zhí)行d和e。

dispatch_barrier_async的順序執(zhí)行還是依賴queue的類型,必需要queue的類型為dispatch_queue_create創(chuàng)建的,而且attr參數(shù)值必需是DISPATCH_QUEUE_CONCURRENT類型。

4.dispatch_apply:

執(zhí)行某個任務(wù)N次。

dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {

// 執(zhí)行10次

});

5.dispatch_semaphore_t:

信號量,用來給線程加鎖,主要有三個函數(shù),創(chuàng)建信號量、等待信號量、發(fā)送信號量

dispatch_semaphore_t lock = dispatch_semaphore_create(1) ?//創(chuàng)建信號量,并指定信號量的初值為1,如果小于0則會返回NULL

dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER) //等待信號量,當(dāng)信號值>0時,使信號值-1;當(dāng)信號值為0時,會阻塞當(dāng)前線程,如果此時有另外一個線程要進(jìn)來訪問資源,則會被堵在外面等待,等信號值>0時再進(jìn)入訪問,由此做到線程安全

dispatch_semaphore_signal(lock) //發(fā)送信號量,使信號值+1

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

相關(guān)閱讀更多精彩內(nèi)容

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