GCD簡介(Grand Central Dispatch)
GCD是從ios4開始引入的新一代多線程編程技術(shù)
GCD需要用到一個(gè)系統(tǒng)庫lib dispatch,lib dispatch是蘋果的一個(gè)開發(fā)庫,我們在使用時(shí)不需要導(dǎo)入這個(gè)庫 因?yàn)橄到y(tǒng)層也在用這個(gè)庫 所以這個(gè)庫不導(dǎo)入它也會(huì)被加載進(jìn)來
使用GCD開發(fā)者只需要定義想要執(zhí)行的任務(wù)并追加到適當(dāng)?shù)腄ispatch Queue中,GCD就能生成必要的線程并有計(jì)劃的執(zhí)行任務(wù),ios的內(nèi)核會(huì)基于DIspatch Queue中的任務(wù)數(shù)量、CPU核數(shù)和CPU負(fù)荷等當(dāng)前的系統(tǒng)狀態(tài)來決定創(chuàng)建多少個(gè)線程和并發(fā)執(zhí)行多少個(gè)任務(wù)
一、Dispatch Queue(調(diào)度隊(duì)列)
使用GCD進(jìn)行編程,開發(fā)者要做的只是定義想要執(zhí)行的任務(wù)并追加到適當(dāng)?shù)腄ispatch Queue中。調(diào)度隊(duì)列中的任務(wù)按照FIFO(先入先出)的順序進(jìn)行處理,也就是先進(jìn)入的任務(wù)現(xiàn)行處理
二、調(diào)度隊(duì)列分為串行和并發(fā)兩種
串行VS并發(fā)
串行:要求等待正在執(zhí)行的任務(wù)完成,再執(zhí)行下一個(gè),也就是說只會(huì)創(chuàng)建一個(gè)線程來執(zhí)行任務(wù)
并發(fā):隊(duì)列中后面的任務(wù)可以不必等待正在執(zhí)行的任務(wù)完成就可以執(zhí)行,也就是同時(shí)可以執(zhí)行多個(gè)任務(wù),也就是說會(huì)創(chuàng)建多個(gè)線程同時(shí)執(zhí)行多個(gè)任務(wù)
1、串行隊(duì)列
創(chuàng)建一個(gè)隊(duì)列會(huì)開辟一個(gè)分線程,添加到串行隊(duì)列中的任務(wù)在新線程中會(huì)按照添加的順興執(zhí)行。串行隊(duì)列經(jīng)常處理一些需要順序訪問的任務(wù)。創(chuàng)建多個(gè)串行隊(duì)列,多個(gè)串行隊(duì)列間是并行的。
創(chuàng)建串行隊(duì)列代碼如下
/**
*? @author沈超, 16-07-15 14:07:33
*
*創(chuàng)建串行隊(duì)列,添加到此隊(duì)列的任務(wù)回一個(gè)挨著一個(gè)執(zhí)行此隊(duì)列會(huì)開辟一條線程執(zhí)行任務(wù)
*
*? @param "com.cmcc.serialQueue"唯一標(biāo)識符,一般域名反寫+隊(duì)列名,用于調(diào)試,崩潰報(bào)告中查看
*? @param NULL指定創(chuàng)建queue的類型,NULL或DISPATCH_QUEUE_SERIAL表示串行隊(duì)列
*
*? @return <#return value description#>
*/
dispatch_queue_tserial_Queue=dispatch_queue_create("com.cmcc.serialQueue",NULL);/**
*? @author沈超, 16-07-15 14:07:10
*
*創(chuàng)建并發(fā)隊(duì)列,添加到此隊(duì)列的任務(wù)會(huì)并發(fā)執(zhí)行,此隊(duì)列會(huì)創(chuàng)建多個(gè)線程執(zhí)行任務(wù)
*
*? @param "com.cmcc.concurrent_queue"唯一標(biāo)識符,一般域名反寫+隊(duì)列名,用于調(diào)試,崩潰報(bào)告中查看
*? @param DISPATCH_QUEUE_CONCURRENT指定創(chuàng)建queue的類型,DISPATCH_QUEUE_SERIAL表示并發(fā)隊(duì)列
*
*? @return <#return value description#>
*/
dispatch_queue_tconcurrent_queue=dispatch_queue_create("com.cmcc.concurrent_queue",DISPATCH_QUEUE_CONCURRENT);
三、系統(tǒng)提供隊(duì)列全局隊(duì)列和主隊(duì)列
①全局隊(duì)列
全局隊(duì)列是一個(gè)在全局都可以獲取的并發(fā)隊(duì)列,而是只需要獲取全局隊(duì)列使用即可。全局隊(duì)列有四種,即4個(gè)優(yōu)先級,分別是high、default、low、background
獲取全局隊(duì)列的代碼如下
dispatch_queue_t dispatch_global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
②主隊(duì)列
主隊(duì)列是一個(gè)在全局都可以獲取的串行調(diào)度隊(duì)列,該隊(duì)列中的任務(wù)都是在主線程中執(zhí)行的。因?yàn)槭窃谥骶€程中執(zhí)行,所以一般會(huì)將用戶界面更新等一些必須在主線程中執(zhí)行的任務(wù)追加帶主隊(duì)列中。
獲取主隊(duì)列代碼如下
dispatch_queue_tmain_queue =dispatch_get_main_queue();
隊(duì)列類型
創(chuàng)建的串行隊(duì)列
創(chuàng)建的并發(fā)隊(duì)列
獲取的全局隊(duì)列
獲取的主隊(duì)列
四、dispatch_async 和 dispatch_sync
任務(wù):定義想要執(zhí)行的任務(wù) 使用block語法來完成
同步提交:dispatch_sync同步添加任務(wù)到隊(duì)列中,它是等待任務(wù)完成之后再繼續(xù)執(zhí)行。
異步提交:dispatch_async異步添加任務(wù)到異步隊(duì)列中,它不會(huì)做任何等待
注意:同步提交不管提交到哪個(gè)什么隊(duì)列,不會(huì)開辟新線程,在當(dāng)前線程中執(zhí)行
特別注意:同步提交要慎重使用,尤其是在當(dāng)前隊(duì)列中同步提交任務(wù)到當(dāng)前隊(duì)列,會(huì)造成線程死鎖
五、dispatch_group
如果想在dispatch_queue中所有的任務(wù)執(zhí)行完成后再做某種操作,在串行隊(duì)列中,可以把該操作放到最后一個(gè)任務(wù)執(zhí)行完成后執(zhí)行,但是在并行隊(duì)列中怎么做呢,這就有了dispatch_group成組操作
創(chuàng)建一個(gè)group
使用dispatch_group_async向組中添加隊(duì)列和任務(wù)
當(dāng)并行隊(duì)列中的任務(wù)執(zhí)行完時(shí),使用dispatch_group_notify執(zhí)行block通知group中的任務(wù)執(zhí)行完畢
六、dispatch_semaphore
dispatch_semaphore信號量記憶計(jì)數(shù)器的一種多線程同步機(jī)制,在多線個(gè)線程訪問共有資源時(shí)候,會(huì)因?yàn)槎嗑€程的特性而引發(fā)數(shù)據(jù)出錯(cuò)的問題。
GCD中有3個(gè)信號量有關(guān)的操作:
dispatch_semaphore_create ? ? 信號量創(chuàng)建
dispatch_semaphore_wait ? ? ? ? 信號量等待 wait會(huì)阻塞線程并且檢測信號量的值,直到信號量值大于0才會(huì)往下執(zhí)行,
同時(shí)對信號量執(zhí)行-1操作
dispatch_semaphore_signal ? ? 發(fā)送通知+1 如果信號量值小于0直接喚醒線程繼續(xù)執(zhí)行
場景1:并發(fā)隊(duì)列中的兩個(gè)操作 操作1完成后操作2才能開始(線程間通信)
場景2:控制并發(fā)隊(duì)列中并發(fā)任務(wù)數(shù)量
七、dispatch_once
使用Dispatch_once函數(shù)實(shí)現(xiàn)單例中的線程同步
該函數(shù)參數(shù)1 dispatch_once用于檢查代碼塊是否已經(jīng)被調(diào)度的謂詞(其實(shí)就是長整形,實(shí)際上作為BOOL使用) 加static使用靜態(tài)變量 以保證只執(zhí)行一次。
參數(shù)2 希望在程序的生命周期內(nèi)僅調(diào)用一次的代碼塊(適用于單例)如果被多個(gè)線程同時(shí)調(diào)用,該函數(shù)會(huì)同步等待,直至代碼塊完成
優(yōu)勢:
1、線程安全
2、僅需要少量代碼塊實(shí)現(xiàn)單例
八、dispatch_barrier_async
在并發(fā)隊(duì)列中,使用dispatch_barrier_async添加的任務(wù),隊(duì)列在執(zhí)行此任務(wù)時(shí),隊(duì)列中的其他任務(wù)不會(huì)執(zhí)行,執(zhí)行完成后該隊(duì)列回復(fù)原有執(zhí)行狀態(tài),繼續(xù)并發(fā)執(zhí)行
當(dāng)一系列的操作都需要依賴于某個(gè)操作時(shí),使用dispatch_barrier_async
注意:使用用戶創(chuàng)建的并發(fā)隊(duì)列(在系統(tǒng)隊(duì)列中阻塞無效,等價(jià)于dispatch_async)
九、Dispatch_apply
Dispatch_apply是Dispatch_sync和dispatch_group的關(guān)聯(lián)API。
dispatch_apply函數(shù)值將指定次數(shù)的指定任務(wù)(block)添加到queue中(此處queue一般為并發(fā)隊(duì)列)
dispatch_apply是同步函數(shù),會(huì)阻塞當(dāng)前線程直到所有循環(huán)中任務(wù)執(zhí)行完成,這些任務(wù)在queue中的執(zhí)行順序是不確定的(要并發(fā),要提高效率)
十、Dispatch_after&&dispatch_time
Tips:
并發(fā)VS并行
并發(fā)指的是同時(shí)執(zhí)行了多個(gè)任務(wù),在多個(gè)任務(wù)間切換,一般是指同一時(shí)間間隔同時(shí)執(zhí)行了多個(gè)任務(wù)(一般指單核)
并行值的是同時(shí)執(zhí)行多個(gè)任務(wù),一般是指同一時(shí)刻同時(shí)執(zhí)行了多少任務(wù)(一般指多核)
并行:(多核)
cpu1:任務(wù)part1
thread:_________________
cpu2:任務(wù)part2
thread:_________________
并發(fā):(單核)
thread1— ? — ? ?— ? ?— ? ?— ? ?— ? — ? —任務(wù)part1
thread2 ? — ? — ? ?— ? ?— ? ?— ? ?— ? ?— ? —任務(wù)part2
并行要求并發(fā),并發(fā)并不能保證并行(單核)