GCD是多線程編程中很常用的技術(shù),同時,作為一項重要的知識點,在面試中也是“常來之客”,本文通過API進行GCD的歸納和總結(jié)

GCD之前
在蘋果引入GCD技術(shù)之前,Cocoa框架中的NSObject類提供了performSelectorInBackground:withObject和performSelectorOnMainThread等來實現(xiàn)多線程編程,此外還有NSThread、NSOperation等,伴隨GCD的誕生,NSOperation也進行重寫,基于GCD實現(xiàn)
關(guān)于多線程編程
一個CPU一次只能執(zhí)行一個命令,這樣連續(xù)執(zhí)行命令,相當于一條無分叉的路徑,這樣的路徑就是“線程”。OS和iOS的核心XNU內(nèi)核在進行操作系統(tǒng)事件處理的時候,會切換執(zhí)行路徑。每條執(zhí)行路徑的狀態(tài),會保存到每條路徑專用的內(nèi)存塊中,便于下次執(zhí)行時復(fù)原信息。這種來回切換的操作可以被稱為“上下文切換”,也正是這種切換產(chǎn)生了多線程。
多線程需要注意的問題
- 數(shù)據(jù)不一致:例如,兩個線程同時更新一個數(shù)據(jù)
- 死鎖:兩個線程互相等待對方執(zhí)行結(jié)束
- 內(nèi)存消耗:線程過多會消耗大量內(nèi)存
...
GCD的API
dispatch_queue_t
分為兩種
-
Serial Dispatch Queue:串行隊列-
系統(tǒng)提供的:
dispatch_get_main_queue -
自定義創(chuàng)建:
dispatch_queue_create("name", DISPATCH_QUEUE_SERIAL)其中的name是該queue的名字
-
系統(tǒng)提供的:
-
Concurrent Dispatch Queue:并行隊列-
系統(tǒng)提供的:
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)其中第一個參數(shù)有四種,對應(yīng)不同優(yōu)先級DISPATCH_QUEUE_PRIORITY_BACKGROUNDDISPATCH_QUEUE_PRIORITY_LOWDISPATCH_QUEUE_PRIORITY_DEFAULTDISPATCH_QUEUE_PRIORITY_HIGH
-
自定義創(chuàng)建:
dispatch_queue_create("name",DISPATCH_QUEUE_CONCURRENT)
-
系統(tǒng)提供的:
dispatch_set_target_queue
-
dispatch_queue_create生成的dispatch_queue_t的優(yōu)先級都是默認優(yōu)先級,如果想要改變優(yōu)先級可以使用:
dispatch_queue_t queue1 = dispatch_queue_create("name", DISPATCH_QUQUE_SERIAL);
dispatch_queue_t queue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND);
dispatch_set_target_queue(queue1, queue2);
- 同時如果將多個串行隊列的目標制定為同一個串行隊列,那么本應(yīng)該并行執(zhí)行的各個串行隊列只能串行地進行執(zhí)行
dispatch_after
在指定時間之后執(zhí)行處理,本質(zhì)上是在指定時間之后將任務(wù)追加到隊列中
dispatch_group_t
隊列組可以用來實現(xiàn):當所有處理結(jié)束之后,執(zhí)行一個操作。正常來說使用串行隊列是很容易實現(xiàn)的,但是如果是并行隊列的話,想要實現(xiàn)這個操作,就需要借助隊列組來實現(xiàn)
dispatch_group_notify
- 用于group中所有任務(wù)執(zhí)行完之后追加一個操作執(zhí)行
- 該方法不會阻塞當前線程
dispatch_group_wait
long result = dispatch_group_wait(group, time);
- 該函數(shù)會阻塞當前線程(即代碼所處的線程)
- time的選擇
- 可以是一個固定的時間,如果超時了,該函數(shù)就會返回
- 也可以是DISPATCH_TIME_FOREVER,表示一直等待,直到group中所有操作執(zhí)行完畢,函數(shù)才返回。
- 返回值
- 0:代表group中的任務(wù)全部執(zhí)行完了
- 非0:代表超時了
dispatch_barrier_async
一般來說,關(guān)于數(shù)據(jù)庫的操作,使用串行隊列能夠避免數(shù)據(jù)異常的問題。但是實際上,讀取操作之間是沒有影響的,為了提高效率,讀取操作通過是并行的,只需要保證寫操作的時候,沒有任何一個讀取操作在進行即可。
dispatch_async(queue, block_reading1);
dispatch_async(queue, block_reading2);
dispatch_barrier_async(queue, block_writing);
dispatch_async(queue, block_reading3);
dispatch_async(queue, block_reading4);
以上代碼中的寫操作,會等待上面代碼中的讀操作(已經(jīng)被添加到隊列中的任務(wù))執(zhí)行完畢之后,開始執(zhí)行,此時,寫操作以下的代碼中的讀操作需要的等待寫操作執(zhí)行完之后才能添加到隊列中執(zhí)行
dispatch_async和dispatch_sync
-
dispatch_async是異步執(zhí)行,代表不會阻塞當前線程,會另外開辟線程執(zhí)行任務(wù) -
dispatch_sync是同步執(zhí)行,代表會阻塞當前線程,會在當前線程執(zhí)行任務(wù)
dispatch_apply
該函數(shù)可以將block中的任務(wù)指定次數(shù)加入到隊列中,并且會阻塞當前線程,直到所有的任務(wù)全部執(zhí)行完
dispatch_suspend和dispatch_resume
-
dispatch_suspend:掛起后,添加到隊列中的任務(wù),尚未執(zhí)行的處理都會停止執(zhí)行 -
dispatch_resume:將會恢復(fù)以上操作
dispatch_semaphore_t
GCD中的信號量,用于控制并行執(zhí)行,在GCD中,控制并行可以通串行隊列和dispatch_barrier_async來做,而信號量semaphore可以更加精確地控制并行
-
dispatch_semaphore_create(number ):number為信號量的初始量 -
dispatch_semaphore_wait(semaphore, time)- 其中time和group中是一樣的
- 返回值:
- 0:如果信號量大于等于1,返回0,同時將信息號量減去1
- 非0:超過指定時間(同時這時信號量為0)
-
dispatch_semaphore_signal(semaphore):將信號量+1
dispatch_once
用于單例處理,相關(guān)代碼只會執(zhí)行一次(即使在多核情況下,也是安全的)