本文是自己寫的總結(jié)GCD的Demo的結(jié)果??偨Y(jié)的過程中,參考了很多文章,文章底部有引用鏈接,在此感謝。
多圖,流量慎點??。
- 概念介紹
- 隊列的創(chuàng)建
- 任務的創(chuàng)建與執(zhí)行
- 實踐運用
- 其他
概念介紹
進程和線程
進程(process):一個執(zhí)行中程序的實例。指的是一個正在運行中的可執(zhí)行文件。每個進程都擁有獨立的虛擬內(nèi)存空間和系統(tǒng)資源,包括端口權(quán)限等,而且至少包含一條主線程(或者可以包括任意數(shù)量的子線程)。當一個進程的主線程退出時,這個進程就結(jié)束了。對于iOS的app來說,一個app運行起來,就是一個進程。

線程:(thread),指定是一個獨立的代碼執(zhí)行路徑,(代碼執(zhí)行的管道),線程是代碼執(zhí)行路徑的最小單位。
同步和異步
同步和異步操作的主要區(qū)別在于是否等待操作執(zhí)行完成,即是否阻塞當前線程。
同步:在發(fā)出一個同步調(diào)用時 ,在沒有得到結(jié)果之前,該調(diào)用就不返回。
異步:在發(fā)出一個異步調(diào)用后,調(diào)用者不會立刻得到結(jié)果,該調(diào)用就返回了。
同步和異步是針對能不能開線程。同步不能開啟新的線程。異步可以。異步雖然有開啟新線程的能力,但不是說只要異步調(diào)用,就開啟新線程了。
在iOS中,同步和異步即針對以下兩個函數(shù)。
- 同步函數(shù):
dispatch_sync(queue, ^{
})
- 異步函數(shù):
dispatch_async(queue, ^{
})
串行和并發(fā)
串行和并發(fā)指的是任務(代碼)的執(zhí)行方式。
串行是指多個任務時,各個任務按順序執(zhí)行,挨個兒進行,完成一個之后才能進行下一個。順序不會亂。
并發(fā)指的是多個任務可以同時(一個時間段內(nèi))執(zhí)行。異步是并發(fā)的前提。
在iOS中,任務的執(zhí)行方式(串行或并發(fā)),由隊列來管理。隊列是用來存放任務的。
隊列和線程
在iOS中,有兩種不同類型的隊列:串行隊列(主隊列是一種特殊的串行隊列)和并發(fā)隊列。串行隊列一次只能執(zhí)行一個任務,并發(fā)隊列則可以允許多個任務同時執(zhí)行。iOS系統(tǒng)是使用這些隊列進行任務調(diào)度的 ,系統(tǒng)會根據(jù)調(diào)度任務的需要和系統(tǒng)當前的負載情況動態(tài)的創(chuàng)建和銷毀線程,不需要我們手動管理線程的銷毀。隊列負責任務的執(zhí)行方式;線程是任務的執(zhí)行通道。
- 串行隊列(Serial Dispatch Queue)
每次只有一個任務被執(zhí)行。讓任務一個接著一個執(zhí)行。 - 并發(fā)隊列 (Concurrent Dispatch Queue)
可以讓多個任務并發(fā)執(zhí)行,在異步調(diào)用的前提下,可以開啟線程,實現(xiàn)并發(fā)。
插個題外話
并發(fā)和并行
- 并發(fā)只是假象的
同時,是單個處理器的計算機的cpu快速的在不同的程序上切換。并行是真正意義上的同時,是多個處理器的計算機,各個cpu在同一時間執(zhí)行不同的程序。
并發(fā)
并行題外話插完了
隊列的創(chuàng)建
GCD中有三種隊列:串行隊列,并發(fā)隊列,主隊列(一種特殊的串行隊列)。
//串行隊列創(chuàng)建
dispatch_queue_t serialQueue = dispatch_queue_create("com.GCDDemo.testSerial", DISPATCH_QUEUE_SERIAL);
//并發(fā)隊列創(chuàng)建
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.GCDDemo.testConcurrent", DISPATCH_QUEUE_CONCURRENT);
創(chuàng)建隊列的函數(shù)有兩個參數(shù),第一個參數(shù)表示隊列的標識符,類似名字的作用,可為空。第二個參數(shù)表示隊列的種類,是串行隊列還是并發(fā)隊列,必填。
除了創(chuàng)建并發(fā)隊列外,還可以直接獲得系統(tǒng)為我們提供的全局并發(fā)隊列。
//獲取全局并發(fā)隊列
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
第一個參數(shù)表示隊列的優(yōu)先級,一般填默認的就可以。第二個參數(shù)是系統(tǒng)預留出來的,填0即可。
//獲取主隊列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
任務的創(chuàng)建與執(zhí)行
//同步執(zhí)行任務創(chuàng)建
dispatch_sync(queue, ^{
// 任務代碼
});
//異步函數(shù)執(zhí)行任務創(chuàng)建
dispatch_async(queue, ^{
//任務代碼
});
上邊函數(shù)的block塊里是一個任務。
因為有兩種調(diào)用創(chuàng)建任務的函數(shù)和兩種隊列,再加上一種特殊的主隊列。所以我們就一共有六種情況,不同的組合跑出來的效果不一樣,先看下這六種組合的區(qū)別。
| 并發(fā)隊列 | 串行隊列 | 主隊列 | |
|---|---|---|---|
| 同步 (sync) | 沒有開啟新線程,串行執(zhí)行任務 | 沒有開新線程,串行執(zhí)行任務 | 如果在主線程中調(diào)用:會出現(xiàn)死鎖,不執(zhí)行。在其他線程中調(diào)用:沒有開新線程,串行執(zhí)行任務 |
| 異步(async) | 會開啟新線程,并發(fā)執(zhí)行任務 | 會開啟一條新線程,串行執(zhí)行任務 | 沒有開啟新線程,串行執(zhí)行任務 |
實踐運用
以下測試中所用到的并發(fā)隊列都用系統(tǒng)提供的全局并發(fā)隊列
-
同步調(diào)用+并發(fā)隊列
同步并發(fā)代碼.png

從運行結(jié)果中可以看出,同步函數(shù)調(diào)用,沒有開線程,任務都是在主線程進行,而且是順序串行執(zhí)行?!驹谥骶€程中運行該方法】

在子線程中運行的話,也一樣是沒有開新的線程,所有任務都是按照順序串行執(zhí)行。
- 同步調(diào)用+串行隊列


主線程中: 同步串行,沒有開啟新線程,所有任務都要按照屬性串行執(zhí)行,【當前同步函數(shù)的調(diào)用,必須等到調(diào)用的函數(shù)執(zhí)行結(jié)束后(即需要將block塊里的任務執(zhí)行完),才能進行下一步】

子線程中,依然是沒有開啟新的線程。所有任務都是按照順序串行執(zhí)行。
-
異步調(diào)用+并發(fā)隊列
異步并發(fā)代碼.png

從運行結(jié)果來看,
結(jié)束是先于函數(shù)調(diào)用block里的任務打印出來,說明異步調(diào)用,不需要函數(shù)(dispatch_async)返回,繼續(xù)往下執(zhí)行,從運行結(jié)果的線程number來看,開了三條子線程,而且不同的任務分別在不同的線程中執(zhí)行。說明異步并發(fā)開啟子線程。

在子線程中調(diào)用異步并發(fā),依然會開啟新的子線程。
- 異步+串行隊列


異步串行在主線程中運行,開啟了一條新的線程執(zhí)行調(diào)用函數(shù)中加的任務。

在子線程中執(zhí)行方法,也會開一條新的子線程執(zhí)行函數(shù)調(diào)用中block中任務。
- 同步調(diào)用+主隊列

程序崩潰 主線程中的任務是在主隊列中的,主隊列是串行隊列 ,任務需要一個個按照順序執(zhí)行。在主線程中調(diào)用了同步函數(shù),這就相當于隊列中加了一個任務1,同步函數(shù)的block里又往主隊列里加了任務2。主隊列中的任務需要依次執(zhí)行。所以任務2的執(zhí)行,需要任務1執(zhí)行完成(同步函數(shù)的調(diào)用返回)。但是任務1的調(diào)用返回必須得block塊里的代碼(即任務2)執(zhí)行完畢才可以。所以兩者相互等待,造成死鎖?!具@里有點繞,不知道自己說的是否清楚??】

如果再子線程里調(diào)用該方法,程序就能按照串行執(zhí)行。不會崩潰。
由上可以得出死鎖發(fā)生的條件
1,隊列是串行隊列。2,調(diào)用同步函數(shù)將任務加到自己的隊列中。
-
異步調(diào)用+主隊列
異步主隊列代碼.png

雖然是異步,但是也沒有開啟子線程,調(diào)用函數(shù)的任務都在主線程中執(zhí)行。

在子線程中,也沒有開啟新的線程。
-
線程間通信,從子線程回到主線程。通信.png
一般會在子線程做耗時工作,任務結(jié)束后,回到主線程更新UI。
其它方法
隊列組






柵欄函數(shù)


柵欄函數(shù),顧名思義,通過柵欄將上下的代碼隔開,真正的運行效果也是隔開了。【我開發(fā)中沒有用到過這個函數(shù)。不清楚用處】
延遲執(zhí)行

一次執(zhí)行(單例)
說到單例,這里有篇談weak關(guān)鍵字的文章,延伸閱讀:弱引用單例

信號量
信號量
GCD中信號量有關(guān)的有三個函數(shù)。
//創(chuàng)建信號量 參數(shù):信號量的初始值。
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
//將信號量減一 參數(shù):信號量,等待時間
// 等待降低信號量,如果代碼執(zhí)行到這里,信號量的值=0,則阻塞當前線程,知道信號量值大于0時,才會進行執(zhí)行這里,同時將信號量減一。
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//信號量加一。
dispatch_semaphore_signal(semaphore);
-
1,線程同步
從圖中運行結(jié)果來看,異步并發(fā)操作,調(diào)用異步函數(shù)時,應該不用等待該函數(shù)返回,直接打印結(jié)束。但是在這里加了信號量的控制。當走到信號量線程同步.pngdispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);時,信號量為0,此時線程阻塞,直到信號量大于0;dispatch_semaphore_signal(semaphore);當走到該行代碼時,信號量加1,信號量等待處開始執(zhí)行。 2,控制最大并發(fā)數(shù)(這個需求用NSOperationQueue會更方便實現(xiàn)。)
總結(jié): 一直想把一些東西總結(jié)下來,有的時候看到了,覺得懂了,但是到用的時候卻不是。經(jīng)過這次的總結(jié),也發(fā)現(xiàn)了一些問題,之后會陸續(xù)更新。作為記錄,也希望能給需要的人以參考,如果有問題,歡迎指出。謝謝????。
最后,再次強調(diào)下:Demo傳送門 ????????歡迎star
參考:http://blog.csdn.net/sinat_35512245/article/details/53836580
http://www.itdecent.cn/p/2d57c72016c6
http://blog.csdn.net/fern_girl/article/details/61197995
http://www.cnblogs.com/kenshincui/p/3983982.html#3913461




