本文是自己寫的總結GCD的Demo的結果九孩。總結的過程中发框,參考了很多文章躺彬,文章底部有引用鏈接,在此感謝梅惯。
多圖宪拥,流量慎點??。
- 概念介紹
- 隊列的創(chuàng)建
- 任務的創(chuàng)建與執(zhí)行
- 實踐運用
- 其他
概念介紹
進程和線程
進程(process)
:一個執(zhí)行中程序的實例铣减。指的是一個正在運行中的可執(zhí)行文件她君。每個進程都擁有獨立的虛擬內存空間和系統(tǒng)資源,包括端口權限等葫哗,而且至少包含一條主線程(或者可以包括任意數(shù)量的子線程)缔刹。當一個進程的主線程退出時,這個進程就結束了魄梯。對于iOS的app來說桨螺,一個app運行起來,就是一個進程酿秸。
線程:(thread)
,指定是一個獨立的代碼執(zhí)行路徑灭翔,(代碼執(zhí)行的管道),線程是代碼執(zhí)行路徑的最小單位辣苏。
同步和異步
同步和異步操作的主要區(qū)別在于是否等待操作執(zhí)行完成肝箱,即是否阻塞當前線程。
同步
:在發(fā)出一個同步調用時 稀蟋,在沒有得到結果之前煌张,該調用就不返回。
異步
:在發(fā)出一個異步調用后退客,調用者不會立刻得到結果骏融,該調用就返回了链嘀。
同步和異步是針對能不能開線程。同步不能開啟新的線程档玻。異步可以怀泊。異步雖然有開啟新線程的能力,但不是說只要異步調用误趴,就開啟新線程了霹琼。
在iOS中,同步和異步即針對以下兩個函數(shù)凉当。
- 同步函數(shù):
dispatch_sync(queue, ^{
})
- 異步函數(shù):
dispatch_async(queue, ^{
})
串行和并發(fā)
串行和并發(fā)指的是任務(代碼)的執(zhí)行方式枣申。
串行
是指多個任務時,各個任務按順序執(zhí)行看杭,挨個兒進行忠藤,完成一個之后才能進行下一個。順序不會亂楼雹。
并發(fā)
指的是多個任務可以同時(一個時間段內)執(zhí)行熄驼。異步是并發(fā)的前提。
在iOS中烘豹,任務的執(zhí)行方式(串行或并發(fā)),由隊列來管理诺祸。隊列是用來存放任務的携悯。
隊列和線程
在iOS中,有兩種不同類型的隊列:串行隊列(主隊列是一種特殊的串行隊列)和并發(fā)隊列筷笨。串行隊列一次只能執(zhí)行一個任務憔鬼,并發(fā)隊列則可以允許多個任務同時執(zhí)行。iOS系統(tǒng)是使用這些隊列進行任務調度的 胃夏,系統(tǒng)會根據(jù)調度任務的需要和系統(tǒng)當前的負載情況動態(tài)的創(chuàng)建和銷毀線程轴或,不需要我們手動管理線程的銷毀。隊列負責任務的執(zhí)行方式仰禀;線程是任務的執(zhí)行通道照雁。
- 串行隊列(Serial Dispatch Queue)
每次只有一個任務被執(zhí)行。讓任務一個接著一個執(zhí)行答恶。 - 并發(fā)隊列 (Concurrent Dispatch Queue)
可以讓多個任務并發(fā)執(zhí)行饺蚊,在異步調用的前提下,可以開啟線程悬嗓,實現(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塊里是一個任務蝌蹂。
因為有兩種調用創(chuàng)建任務的函數(shù)和兩種隊列,再加上一種特殊的主隊列曹锨。所以我們就一共有六種情況孤个,不同的組合跑出來的效果不一樣,先看下這六種組合的區(qū)別沛简。
并發(fā)隊列 | 串行隊列 | 主隊列 | |
---|---|---|---|
同步 (sync) | 沒有開啟新線程齐鲤,串行執(zhí)行任務 | 沒有開新線程,串行執(zhí)行任務 | 如果在主線程中調用:會出現(xiàn)死鎖椒楣,不執(zhí)行给郊。在其他線程中調用:沒有開新線程,串行執(zhí)行任務 |
異步(async) | 會開啟新線程捧灰,并發(fā)執(zhí)行任務 | 會開啟一條新線程,串行執(zhí)行任務 | 沒有開啟新線程淆九,串行執(zhí)行任務 |
實踐運用
以下測試中所用到的并發(fā)隊列都用系統(tǒng)提供的全局并發(fā)隊列
-
同步調用+并發(fā)隊列
同步并發(fā)代碼.png
從運行結果中可以看出,同步函數(shù)調用凤壁,沒有開線程吩屹,任務都是在主線程進行,而且是順序串行執(zhí)行拧抖∶核眩【在主線程中運行該方法】
在子線程中運行的話,也一樣是沒有開新的線程唧席,所有任務都是按照順序串行執(zhí)行擦盾。
- 同步調用+串行隊列
主線程中: 同步串行嘲驾,沒有開啟新線程,所有任務都要按照屬性串行執(zhí)行迹卢,【當前同步函數(shù)的調用辽故,必須等到調用的函數(shù)執(zhí)行結束后(即需要將block塊里的任務執(zhí)行完),才能進行下一步】
子線程中腐碱,依然是沒有開啟新的線程誊垢。所有任務都是按照順序串行執(zhí)行。
-
異步調用+并發(fā)隊列
異步并發(fā)代碼.png
從運行結果來看症见,
結束
是先于函數(shù)調用block里的任務打印出來喂走,說明異步調用,不需要函數(shù)(dispatch_async)返回谋作,繼續(xù)往下執(zhí)行芋肠,從運行結果的線程number來看,開了三條子線程遵蚜,而且不同的任務分別在不同的線程中執(zhí)行帖池。說明異步并發(fā)開啟子線程。
在子線程中調用異步并發(fā)吭净,依然會開啟新的子線程睡汹。
- 異步+串行隊列
異步串行在主線程中運行,開啟了一條新的線程執(zhí)行調用函數(shù)中加的任務寂殉。
在子線程中執(zhí)行方法帮孔,也會開一條新的子線程執(zhí)行函數(shù)調用中block中任務。
- 同步調用+主隊列
程序崩潰 主線程中的任務是在主隊列中的不撑,主隊列是串行隊列 ,任務需要一個個按照順序執(zhí)行晤斩。在主線程中調用了同步函數(shù)焕檬,這就相當于隊列中加了一個任務1,同步函數(shù)的block里又往主隊列里加了任務2澳泵。主隊列中的任務需要依次執(zhí)行实愚。所以任務2的執(zhí)行,需要任務1執(zhí)行完成(同步函數(shù)的調用返回)兔辅。但是任務1的調用返回必須得block塊里的代碼(即任務2)執(zhí)行完畢才可以腊敲。所以兩者相互等待,造成死鎖维苔∨龈ǎ【這里有點繞,不知道自己說的是否清楚??】
如果再子線程里調用該方法介时,程序就能按照串行執(zhí)行没宾。不會崩潰凌彬。
由上可以得出死鎖發(fā)生的條件
1,隊列是串行隊列循衰。2铲敛,調用同步函數(shù)將任務加到自己的隊列中。
-
異步調用+主隊列
異步主隊列代碼.png
雖然是異步会钝,但是也沒有開啟子線程伐蒋,調用函數(shù)的任務都在主線程中執(zhí)行。
在子線程中迁酸,也沒有開啟新的線程先鱼。
-
線程間通信,從子線程回到主線程胁出。通信.png
一般會在子線程做耗時工作型型,任務結束后,回到主線程更新UI全蝶。
其它方法
隊列組
柵欄函數(shù)
柵欄函數(shù)闹蒜,顧名思義,通過柵欄將上下的代碼隔開抑淫,真正的運行效果也是隔開了绷落。【我開發(fā)中沒有用到過這個函數(shù)始苇。不清楚用處】
延遲執(zhí)行
一次執(zhí)行(單例)
說到單例砌烁,這里有篇談weak關鍵字的文章,延伸閱讀:弱引用單例
信號量
信號量
GCD中信號量有關的有三個函數(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生年,線程同步
信號量線程同步.pngdispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
時蹲蒲,信號量為0番甩,此時線程阻塞,直到信號量大于0届搁;dispatch_semaphore_signal(semaphore)缘薛;
當走到該行代碼時,信號量加1卡睦,信號量等待處開始執(zhí)行宴胧。 2,控制最大并發(fā)數(shù)(這個需求用NSOperationQueue會更方便實現(xiàn)表锻。)
總結: 一直想把一些東西總結下來恕齐,有的時候看到了,覺得懂了瞬逊,但是到用的時候卻不是显歧。經過這次的總結,也發(fā)現(xiàn)了一些問題确镊,之后會陸續(xù)更新士骤。作為記錄,也希望能給需要的人以參考蕾域,如果有問題拷肌,歡迎指出。謝謝????旨巷。
最后巨缘,再次強調下:Demo傳送門 ????????歡迎star
參考:http://blog.csdn.net/sinat_35512245/article/details/53836580
http://www.reibang.com/p/2d57c72016c6
http://blog.csdn.net/fern_girl/article/details/61197995
http://www.cnblogs.com/kenshincui/p/3983982.html#3913461