一. GCD 簡介
充分利用多核來處理相關(guān)任務(wù),它是一個(gè)在線程池模式的基礎(chǔ)上執(zhí)行的并發(fā)任務(wù)
二.GCD 任務(wù)和隊(duì)列
任務(wù):
就是在GCD里的block,執(zhí)行任務(wù)的方式有兩種,『同步』和『異步』。
同步執(zhí)行(sync):
不具備開起線程的能力,同步添加任務(wù)到指定的隊(duì)列中,在添加的任務(wù)執(zhí)行結(jié)束之前,會(huì)一直等待,直到隊(duì)列里面的任務(wù)完成之后再繼續(xù)執(zhí)行。
異步執(zhí)行(async):
具備開起線程的能力,異步添加任務(wù)到指定的隊(duì)列中,它不會(huì)做任何等待,可以繼續(xù)執(zhí)行任務(wù)
舉個(gè)例子:需要打電話給小明和小白。
同步執(zhí)行:只有一個(gè)手機(jī)(當(dāng)前線程),必須等待和小明的同話結(jié)束才能打給小白
異步執(zhí)行:有兩個(gè)或者多個(gè)手機(jī)(多個(gè)線程),不必等待,用第二個(gè)手機(jī)打給小白
注意:異步執(zhí)行(async)雖然具有開啟新線程的能力,但是并不一定開啟新線程
隊(duì)列(Dispatch Queue):
用來存放任務(wù)的隊(duì)列,隊(duì)列都是先進(jìn)先出的,新的任務(wù)被追加到隊(duì)列的未尾,讀取執(zhí)行的任務(wù)都是從隊(duì)列的開頭取出任務(wù)
例:即將取出任務(wù)1執(zhí)行【任務(wù)1,任務(wù)2,任務(wù)3】添加新任務(wù)4追加到隊(duì)列末尾,【】代表隊(duì)列
在 GCD 中有兩種隊(duì)列:『串行隊(duì)列』 和 『并發(fā)隊(duì)列』。兩者的主要區(qū)別是:執(zhí)行順序不同,以及開啟線程數(shù)不同。
『串行隊(duì)列(Serial Dispatch Queue)』:一個(gè)任務(wù)執(zhí)行完成才能執(zhí)行下一個(gè)任務(wù)
『并發(fā)隊(duì)列(Serial Dispatch Queue)』:多個(gè)任務(wù)可以同時(shí)執(zhí)行(該能力只在并發(fā)隊(duì)列異步執(zhí)行下才有)
三.GCD 使用
1.創(chuàng)建隊(duì)列(串行或并發(fā)隊(duì)列)
2.將任務(wù)添加到隊(duì)列中(同步或異步),然后系統(tǒng)會(huì)自動(dòng)執(zhí)行隊(duì)列中的任務(wù)
3.1 隊(duì)列創(chuàng)建和系統(tǒng)已有的隊(duì)列獲取
//串行隊(duì)列
let syncQueue:DispatchQueue = DispatchQueue.init(label: "SYNC_QUEUE")//默認(rèn)串行隊(duì)列
//并發(fā)隊(duì)列
let asyncQqueue:DispatchQueue = DispatchQueue.init(label: "ASYNC_QUEUE", attributes: .concurrent)
//主隊(duì)列:實(shí)質(zhì)上就是一個(gè)普通的串行隊(duì)列,當(dāng)前編寫的代碼都會(huì)放在主線程上執(zhí)行
let mainQueue:DispatchQueue = DispatchQueue.main
//全局并發(fā)隊(duì)列:實(shí)質(zhì)上就是一個(gè)普通的并發(fā)隊(duì)列
let globalQueue:DispatchQueue = DispatchQueue.global()
3.2任務(wù)創(chuàng)建
queue取決于上面四種隊(duì)列
//同步執(zhí)行任務(wù)的創(chuàng)建
queue.sync {
//任務(wù)的具體實(shí)現(xiàn)
}
//異步執(zhí)行任務(wù)的創(chuàng)建
queue.async {
//任務(wù)的具體實(shí)現(xiàn)
}
四種隊(duì)列和兩種任務(wù)執(zhí)行方式的不同組合如下:
區(qū)別如下:同步+串行隊(duì)列
異步+串行隊(duì)列
同步+并發(fā)隊(duì)列
異步+并發(fā)隊(duì)列
同步+主隊(duì)列
異步+主隊(duì)列
同步+全局隊(duì)列
異步+全局隊(duì)列

注意:不能在該串行隊(duì)列中同步添加任務(wù)到該串行隊(duì)列,否則會(huì)造成死鎖,
func deadLock(){
/****** 在該串行隊(duì)列中同步添加任務(wù)到該串行隊(duì)列才會(huì)造成死鎖 ******/
DispatchQueue.main.sync {//死鎖
print("任務(wù)1")
}
}
func deadLock(){
/****** 在該串行隊(duì)列中同步添加任務(wù)到該串行隊(duì)列才會(huì)造成死鎖 ******/
queueSync.sync {
print("任務(wù)1")
self.queueSync.sync {//死鎖
print("任務(wù)2")
}
print("end")
}
}
死鎖原因:串行隊(duì)列中追加的同步任務(wù)1,當(dāng)同步任務(wù)1正執(zhí)行時(shí),添加同步任務(wù)2,此時(shí)需要等待任務(wù)1執(zhí)行完畢才能執(zhí)行任務(wù)2,而任務(wù)1執(zhí)行完畢需要等待任務(wù)2執(zhí)行完畢,相互等待,最終死鎖,主隊(duì)列也是如此,死鎖這種情況多見于同一個(gè)串行隊(duì)列的嵌套使用。
以下是幾種不同組合的例子:
同步異步+串行隊(duì)列
/**
* 同步執(zhí)行 + 串行隊(duì)列
* 特點(diǎn):在當(dāng)前線程中執(zhí)行任務(wù),不會(huì)開啟新線程,執(zhí)行完一個(gè)任務(wù),再執(zhí)行下一個(gè)任務(wù)。
*/
func syncSerial(){
print("currentThread---\(Thread.current)")
print("begin")
let queue:DispatchQueue = DispatchQueue.init(label: "syncSerial")
queue.sync {
sleep(4)
print("1---\(Thread.current)")
}
queue.sync {
sleep(2)
print("2---\(Thread.current)")
}
queue.sync {
print("3---\(Thread.current)")
}
print("end")
}
輸出:currentThread---<NSThread: 0x170071c80>{number = 1, name = main}
begin
1---<NSThread: 0x170071c80>{number = 1, name = main}
2---<NSThread: 0x170071c80>{number = 1, name = main}
3---<NSThread: 0x170071c80>{number = 1, name = main}
end
同步(sync)執(zhí)行任務(wù)不具有開啟線程的能力,所以共用一個(gè)主線程,一個(gè)任務(wù)執(zhí)行完畢才能執(zhí)行下一個(gè)任務(wù)
/**
* 異步執(zhí)行 + 串行隊(duì)列
* 特點(diǎn):開啟一條新線程,執(zhí)行完一個(gè)任務(wù),再執(zhí)行下一個(gè)任務(wù),主線程不再等待
*/
func asyncSerial(){
print("currentThread---\(Thread.current)")
print("begin")
let queue:DispatchQueue = DispatchQueue.init(label: "asyncSerial")
queue.async {
sleep(4)
print("1---\(Thread.current)")
}
queue.async {
sleep(2)
print("2---\(Thread.current)")
}
queue.async {
print("3---\(Thread.current)")
}
print("end")
}
currentThread---<NSThread: 0x174074880>{number = 1, name = main}
begin
end
1---<NSThread: 0x1702684c0>{number = 3, name = (null)}
2---<NSThread: 0x1702684c0>{number = 3, name = (null)}
3---<NSThread: 0x1702684c0>{number = 3, name = (null)}
異步(async)執(zhí)行任務(wù)具有開啟新線程的能力,且主線程不等待輸出end,但串行隊(duì)列只開啟一條線程,且任務(wù)一個(gè)執(zhí)行完畢才能執(zhí)行下一個(gè)
同步異步+并發(fā)隊(duì)列
/**
* 同步執(zhí)行 + 并發(fā)隊(duì)列
* 特點(diǎn):在當(dāng)前線程中執(zhí)行任務(wù),不會(huì)開啟新線程,執(zhí)行完一個(gè)任務(wù),再執(zhí)行下一個(gè)任務(wù)。
*/
func syncConcurrent(){
print("currentThread---\(Thread.current)")
print("begin")
let queue:DispatchQueue = DispatchQueue.init(label: "syncConcurrent", attributes: .concurrent)
queue.sync {
sleep(4)
print("1---\(Thread.current)")
}
queue.sync {
sleep(2)
print("2---\(Thread.current)")
}
queue.sync {
print("3---\(Thread.current)")
}
print("end")
}
>輸出:
>currentThread---<NSThread: 0x1700730c0>{number = 1, name = main}
>begin
>1---<NSThread: 0x1700730c0>{number = 1, name = main}
>2---<NSThread: 0x1700730c0>{number = 1, name = main}
>3---<NSThread: 0x1700730c0>{number = 1, name = main}
>end
同步(sync)執(zhí)行任務(wù)不具有開啟線程的能力,并發(fā)列隊(duì)只在異步(async)執(zhí)行任務(wù)的時(shí)候才會(huì)開啟新的線程且并發(fā)執(zhí)行任務(wù),所以當(dāng)前共用一個(gè)線程(主線程),同步(sync)執(zhí)行任務(wù)需要一個(gè)執(zhí)行完畢才能執(zhí)行下一個(gè)
/**
* 異步執(zhí)行 + 并發(fā)隊(duì)列
* 特點(diǎn):隊(duì)列開啟新線程執(zhí)行任務(wù),主線程不再等待
*/
func asyncConcurrent(){
print("asyncConcurrent---\(Thread.current)")
print("begin")
let aqueue:DispatchQueue = DispatchQueue.init(label: "asyncConcurrent", attributes: .concurrent)
aqueue.async {
sleep(3)
print("1---\(Thread.current)")
}
aqueue.async {
sleep(2)
print("2---\(Thread.current)")
}
aqueue.async {
sleep(1)
print("3---\(Thread.current)")
}
print("end")
}
>輸出:asyncConcurrent---<NSThread: 0x17006f740>{number = 1, name = main}
>begin
>end
>3---<NSThread: 0x170263840>{number = 3, name = (null)}
>2---<NSThread: 0x170263ac0>{number = 4, name = (null)}
>1---<NSThread: 0x170263b80>{number = 5, name = (null)}
異步(async)執(zhí)行任務(wù)具有開啟線程能力,所以當(dāng)前主線程不等待繼續(xù)執(zhí)行下面代碼輸出end,并發(fā)隊(duì)列開啟新的線程并在該線程中執(zhí)行任務(wù)
同步異步+主隊(duì)列
/**
* 同步執(zhí)行 + 主隊(duì)列
* 特點(diǎn):死鎖
*/
func syncMain(){
print("syncMain---\(Thread.current)")
print("begin")
DispatchQueue.main.sync {
//任務(wù)1
print("1---\(Thread.current)")
}
print(" end")
}
syncMain---<NSThread: 0x17006dec0>{number = 1, name = main}
begin
(lldb)
主隊(duì)列是一個(gè)串行隊(duì)列。這里是因?yàn)楫?dāng)系統(tǒng)執(zhí)行syncMain方法,相當(dāng)于把syncMain任務(wù)放到主隊(duì)列里,而執(zhí)行syncMain的過程中添加了任務(wù)1到主隊(duì)列中,syncMain執(zhí)行完畢需要待任務(wù)1執(zhí)行完,任務(wù)1執(zhí)行完需要等待syncMain執(zhí)行完,互相等待,所以死鎖
/**
* 異步執(zhí)行 + 主隊(duì)列
* 特點(diǎn):在當(dāng)前線程中執(zhí)行任務(wù),不會(huì)開啟新線程,執(zhí)行完一個(gè)任務(wù),再執(zhí)行下一個(gè)任務(wù)。
*/
func asyncMain(){
print("asyncMain---\(Thread.current)")
print("begin")
let aqueue:DispatchQueue = DispatchQueue.main
aqueue.async {
sleep(3)
print("1---\(Thread.current)")
}
aqueue.async {
sleep(2)
print("2---\(Thread.current)")
}
aqueue.async {
sleep(1)
print("3---\(Thread.current)")
}
print("end")
}
asyncMain---<NSThread: 0x174067300>{number = 1, name = main}
begin
end
1---<NSThread: 0x174067300>{number = 1, name = main}
2---<NSThread: 0x174067300>{number = 1, name = main}
3---<NSThread: 0x174067300>{number = 1, name = main}
異步執(zhí)行不會(huì)做任何等待,可以繼續(xù)執(zhí)行任務(wù),雖然異步執(zhí)行可以開啟新的線程,但主隊(duì)列是串行隊(duì)列本身已存在主線程,所以此處不再開啟新的線程。
全局并發(fā)隊(duì)列跟普通并發(fā)隊(duì)列并無區(qū)別
相關(guān)簡書:
iOS GCD學(xué)習(xí)總結(jié)(二)
iOS 線程同步方案學(xué)習(xí)總結(jié)
信號(hào)量semaphore學(xué)習(xí)總結(jié)
iOS dispatch_barrier_sync實(shí)現(xiàn)多讀單寫
NSOperation和NSOperationQueue學(xué)習(xí)總結(jié)