1.理解GCD是什么
GCD是蘋果為多核并行提出的解決方案弦讽。
GCD不需要關(guān)注線程的管理(線程的創(chuàng)建污尉、調(diào)度任務(wù)、線程的銷毀),只聚焦任務(wù)被碗。
2.理解任務(wù)和線程的關(guān)系
具體操作(block里的操作)就是一個任務(wù)某宪,GCD函數(shù)會把任務(wù)放進(jìn)我們指定的隊列(Queue),遵循“先進(jìn)先出锐朴,后進(jìn)后出”的原則缩抡,底層會有任務(wù)調(diào)度,把隊列里的任務(wù)取出分配給線程包颁,GCD隊列只是組織待執(zhí)行任務(wù)的一個數(shù)據(jù)結(jié)構(gòu)封裝瞻想,最終線程去執(zhí)行這些任務(wù)。
3.同步娩嚼、異步任務(wù) ? ? ? ? ? ? ? ? 串行蘑险、并行隊列
任務(wù):就是執(zhí)行操作的意思,換句話說就是你在線程中執(zhí)行的那段代碼岳悟。在GCD中是放在block中的佃迄。執(zhí)行任務(wù)有兩種方式:同步執(zhí)行和異步執(zhí)行。兩者的主要區(qū)別是:是否具備開啟新線程的能力贵少。
同步執(zhí)行(sync):只能在當(dāng)前線程中執(zhí)行任務(wù)呵俏,不具備開啟新線程的能力
異步執(zhí)行(async):可以在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力
隊列:這里的隊列指任務(wù)隊列滔灶,即用來存放任務(wù)的隊列普碎。隊列是一種特殊的線性表,采用FIFO(先進(jìn)先出)的原則录平,即新任務(wù)總是被插入到隊列的末尾麻车,而讀取任務(wù)的時候總是從隊列的頭部開始讀取。每讀取一個任務(wù)斗这,則從隊列中釋放一個任務(wù)动猬。在GCD中有兩種隊列:串行隊列和并行隊列。
并行隊列(Concurrent Dispatch Queue):可以讓多個任務(wù)并行(同時)執(zhí)行(自動開啟多個線程同時執(zhí)行任務(wù))
并行功能只有在異步(dispatch_async)函數(shù)下才有效
串行隊列(Serial Dispatch Queue):讓任務(wù)一個接著一個地執(zhí)行(一個任務(wù)執(zhí)行完畢后表箭,再執(zhí)行下一個任務(wù))
(1) main queue:? (主隊列)? dispatch_get_main_queue()
(2) global queue:? (全局隊列) dispatch_get_global_queue
(3)custom queue: 自定義隊列:可以創(chuàng)建串行隊列和并行隊列
// 串行隊列的創(chuàng)建方法
dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
// 并行隊列的創(chuàng)建方法
dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);
但是既然我們有兩種隊列赁咙,兩種任務(wù)執(zhí)行方式,那么我們就有了四種不同的組合方式免钻。這四種不同的組合方式是
并行隊列 + 同步執(zhí)行
并行隊列 + 異步執(zhí)行
串行隊列 + 同步執(zhí)行
串行隊列 + 異步執(zhí)行
實際上彼水,我們還有一種特殊隊列是主隊列,那樣就有六種不同的組合方式了
主隊列 + 同步執(zhí)行
主隊列 + 異步執(zhí)行
4.造成死鎖的本質(zhì)原因以及解決方法
GCD死鎖的原因是隊列阻塞伯襟,而不是線程阻塞猿涨!
那么我們可以總結(jié)出GCD被阻塞(blocking)的原因有以下兩點:
1.GCD函數(shù)未返回,會阻塞正在執(zhí)行的任務(wù)
2.隊列的執(zhí)行室容量太小姆怪,在執(zhí)行室有空位之前,會阻塞同一個隊列中在等待的任務(wù)
注意:阻塞(blocking)和死鎖(deadlock)是不同的意思,阻塞表示需要等待A事件完成后才能完成B事件稽揭,稱作A會阻塞B俺附,通俗來講就是強(qiáng)制等待的意思。而死鎖表示由于某些互相阻塞溪掀,也就是互相的強(qiáng)制等待事镣,形成了閉環(huán),導(dǎo)致大家永遠(yuǎn)互相阻塞下去了揪胃,Always and Forever璃哟,也就是死鎖。
以上兩點阻塞情景喊递,同時只出現(xiàn)一個随闪,并不會出現(xiàn)死鎖,但是如果兩個同時出現(xiàn)骚勘,就會出現(xiàn)阻塞閉環(huán),造成死鎖俏讹。因此,造成GCD死鎖的原因就是同時具備這兩個因素
#################################################################################################
#方法1:解決GCD函數(shù)未返回造成的阻塞
dispatch_async是異步函數(shù)户矢,具備開啟新線程的能力,但是不一定會開啟新線程殉疼,交給它的block逗嫡,可能在任何線程執(zhí)行,開發(fā)者無法控制驱证,是GCD底層在控制恋腕。它會立即返回抹锄,不會等待block被執(zhí)行。
#方法2:解決隊列(Queue)阻塞
1.為隊列的執(zhí)行室擴(kuò)容荠藤,讓它可以并發(fā)執(zhí)行多個任務(wù)伙单,那么就不會因為A任務(wù),造成B任務(wù)被阻塞了吻育。
首先來說第一個思路淤井,如何為隊列的執(zhí)行室擴(kuò)容呢布疼?我們當(dāng)然沒有辦法為執(zhí)行室擴(kuò)容,但是我們可以選擇用容量大的隊列砾层。使用并發(fā)隊列替代串行隊列贱案。因為并發(fā)隊列的執(zhí)行室可以同時容納若干任務(wù)
2.把A和B任務(wù)放在兩個不同的隊列中肛炮,A就再也沒有機(jī)會阻塞B了宝踪。因為每個隊列都有自己的執(zhí)行室。
我們自己新建了一個串行隊列瘩燥,將block放入自己的串行隊列,不再和viewDidLoad()處于一個隊列悲幅,解決了隊列阻塞站蝠,因此避免了死鎖問題肋坚。
override func viewDidLoad() {
super.viewDidLoad()
print("Start \(NSThread.currentThread())")
let serialQueue = dispatch_queue_create("這是一個串行隊列", DISPATCH_QUEUE_SERIAL)
dispatch_sync(serialQueue, {
for i in 0...100{
print("\(i) \(NSThread.currentThread())")
}
})
詳細(xì)請看鏈接:http://www.reibang.com/p/bbabef8aa1fe
5.GCD其他的使用方法
(1)一次性代碼:單例使用
(2)延時執(zhí)行
聲明:本文非原創(chuàng)蝇棉,僅僅整理一些開發(fā)技能知識文章,以作存檔學(xué)習(xí)用
【1】http://www.reibang.com/p/bbabef8aa1fe// 死鎖的解釋和 1 不同聚蝶,似乎是可以解釋通
【2】鏈接:http://www.reibang.com/p/6f6e995c3f7a
【3】http://www.reibang.com/p/6f6e995c3f7a