? ? ? ?最近一直沒有更新簡書是因為在開發(fā)和測試階段礁芦,有任務(wù),沒有進行學(xué)習(xí)蔑担,不過在做任務(wù)的時候也遇到了一些技術(shù)點,在這里總結(jié)一下咽白。
? ? ? ?今天我們來深度學(xué)習(xí)GCD啤握。深度學(xué)習(xí)我們可以理解為進階學(xué)習(xí),該文試圖用demo里面的栗子形象學(xué)習(xí)GCD的用法晶框。
? ? ? 其實在我們平時的開發(fā)過程中排抬,這個GCD甚至多線程用的并不多,就像算法授段,我們在開發(fā)過程中用的并不多蹲蒲,但是這些知識確實是考驗我們基礎(chǔ)是否扎實的一個標準,還是之前說過的:java和OC或者別的語言侵贵,只是語言形式不同罷了届搁,實際運用的計算機思想是通用的。所以我們通過學(xué)習(xí)GCD,可以以此為突破口卡睦,進而熟知多線程相關(guān)的知識宴胧。“管中窺豹表锻,可見一斑”:比喻從觀察到的部分恕齐,可以推測全貌。類似的我們舉一反三:“冰山一角瞬逊,可見冰山”显歧,哈哈哈。码耐。追迟。
? ? ?1、死鎖
? ? 昨天看到一個面試題骚腥,題目如下:
? ? ? ? 通過上邊的解釋我們可以看出敦间,主線程中同步插入一個主線程的隊列,會造成主線程等著插入的線程完成后才會進行束铭,而要插入的線程完成廓块,那么主線程必須完成,這樣就形成了契沫,你中有我我中有你互相引用的問題带猴,就好像循環(huán)引用似的,互相牽制懈万,結(jié)果大事未了拴清,含恨而終。会通。口予。
? ? ? ? 那么我們?nèi)绻迦氲木€程不是主線程呢,我們試試看涕侈。
? ? ? ?這里我在打印4之后沪停,給主線程插入一個同步隊列queue1,這樣的話裳涛,主線程會被阻塞木张,等待dispath_sync的block執(zhí)行完成后再繼續(xù)執(zhí)行,打印出5來了端三,然后主線程繼續(xù)執(zhí)行打印6舷礼。
我們再來看下邊的這段代碼:
結(jié)果在上圖,只打印了4和5郊闯,我們分析這段代碼:打印4且轨,同步之行queue1隊列浮声,打印5,再同步執(zhí)行queue1隊列旋奢,我們知道dispath_sync是需要等待block里面的結(jié)果出來后再進行下邊的執(zhí)行步驟的,這里造成死鎖:后邊的queue1等待前邊的queue1執(zhí)行完成后才進行后邊的步驟然痊,但是前面的queue1也在等待后邊的queue1執(zhí)行完成至朗,這樣造成死鎖。
由此我們可以得出:dispath_sync不能執(zhí)行所在的線程的線程剧浸,不能執(zhí)行所在隊列中的隊列锹引,不然就會造成死鎖。
我們再來看下邊的代碼:
這里我們更能理解async和sync的區(qū)別:
這里如果我不打斷點唆香,會一直打印4嫌变,而且我們看左上角那里會看到CPU消耗時99%,電量顯示時high躬它。
我們這時候來看一些概念性的知識:
2腾啥、什么是GCD、GCD的優(yōu)勢
(1)GCD全稱是Grand?Central Dispatch冯吓,可以為“偉大的中樞調(diào)度”倘待。純C語言,提供了非常多且強大的函數(shù)
(2)優(yōu)勢
GCD是蘋果公司為多核的并行運算提出的解決方案
GCD會自動利用更多的CPU內(nèi)核(比如雙核组贺、四核)
GCD會自動管理線程的生命周期(創(chuàng)建線程凸舵、調(diào)度任務(wù)、銷毀線程)
程序員只需要告訴GCD想要執(zhí)行什么任務(wù)失尖,不需要編寫任何線程管理代碼
3啊奄、什么是任務(wù)和隊列
GCD中有2個核心概念
(1)任務(wù):執(zhí)行什么操作
(2)隊列:用來存放任務(wù)
GCD的使用就2個步驟(1)定制任務(wù)(2)確定想做的事情
將任務(wù)添加到隊列中,GCD會自動將隊列中的任務(wù)取出掀潮,放到對應(yīng)的線程中執(zhí)行
提示:任務(wù)的取出遵循隊列的FIFO原則:先進先出菇夸,后進后出
4院究、執(zhí)行任務(wù)
1)GCD中有2個用來執(zhí)行任務(wù)的函數(shù)炼吴,即同步方式、異步方式執(zhí)行任務(wù)
dispatch_sync(dispatch_queue_t queue,dispatch_block_t block);
dispatch_async(dispatch_queue_t queue,dispatch_block_t block);
block里面的東西哆致,就是你準備交給隊列queue處理的任務(wù)
2)同步邑商、異步摄咆、串行、并發(fā)
同步和異步?jīng)Q定要不要開啟新的線程
同步:在當前線程中執(zhí)行任務(wù)人断,不具備開啟新線程的能力
異步:在新的線程中執(zhí)行任務(wù)吭从,具備開啟新線程的能力
串行和并行決定任務(wù)的執(zhí)行方式
串行:一個任務(wù)執(zhí)行完畢后,再執(zhí)行下一個任務(wù)
并發(fā):多個任務(wù)并發(fā)(同時)執(zhí)行
5恶迈、怎么獲取線程
1)創(chuàng)建隊列方法
dispatch_queue_create(const?char *label, dispatch_queue_attr_t attr) ? //創(chuàng)建隊列涩金,在非ARC中要手動釋放谱醇。這個方法既可以創(chuàng)建串行隊列,也可以創(chuàng)建并發(fā)隊列
注意:第一個參數(shù)是字符指針步做,表示隊列名稱副渴,第二個是隊列的屬性(傳NULL或DISPATCH_QUEUE_SERIAL都表示的是串行隊列,傳DISPATCH_QUEUE_CONCURRENT全度,表示并發(fā)隊列)
dispatch_get_main_queue(); ? //使用它時煮剧,要注意死鎖,因為不論是同步還是異步執(zhí)行他将鸵,都不會開辟新的線程勉盅,他會在主隊列執(zhí)行
dispatch_get_global_queue(long identifier, unsigned?long flags) ? //并發(fā)隊列,第一個參數(shù)是設(shè)置優(yōu)先級的顶掉,后一個參數(shù)是為將來使用草娜,可以傳0
從上面可以看出:queue如果是串行隊列,那么痒筒,會開辟一個新的線程宰闰,但是,是前一個執(zhí)行完畢凸克,再執(zhí)行后一個议蟆。并發(fā)隊列會開啟兩個線程,并發(fā)執(zhí)行萎战。
討論:哪些會死鎖咐容?死鎖的原因是什么?開辟了新線程么蚂维?
<1>同步執(zhí)行同一個串行隊列
<2>異步執(zhí)行同一個串行隊列
<3>同步異步執(zhí)行同一個串行隊列
<4>異步同步執(zhí)行同一個串行隊列
<5>異步執(zhí)行不同串行隊列
<6>同步執(zhí)行主隊列
<7>同步執(zhí)行不同串行隊列
<8>異步同步執(zhí)行不同串行隊列
<9>同步異步執(zhí)行不同串行隊列
<10>同步執(zhí)行不同并發(fā)隊列
<11>同步異步執(zhí)行同一個并發(fā)隊列
<12>異步同步執(zhí)行同一個并發(fā)隊列
<13>異步執(zhí)行不同并發(fā)隊列
<14>異步執(zhí)行同一個/不同并發(fā)隊列
6戳粒、總攬
1、圖片總體看看GCD
延時方法舉個栗子虫啥,看時間:
注: dispatch_after 函數(shù)并不是在指定時間后執(zhí)行處理蔚约,而是在指定時間后追加處理到Dispatch Queue。例如Main Dispatch Queue在主線程的RunLoop中執(zhí)行涂籽。所以在比如每隔1/60秒執(zhí)行的RunLoop苹祟,Block最快在3秒后執(zhí)行,最慢在 3+1/60秒后執(zhí)行评雌。所以上圖中树枫,performSelector和NSTimer的延時執(zhí)行比我們設(shè)定的2秒和4秒分別晚了4毫秒和3毫秒,但是我們再看dispatchAfter的延時執(zhí)行景东,晚了0.582秒砂轻,即582毫秒。
2. dispatch_barrier_async的作用是什么斤吐?(dispatch柵欄)
在并行隊列中搔涝,為了保持某些任務(wù)的順序厨喂,需要等待一些任務(wù)完成后才能繼續(xù)進行,使用 barrier 來等待之前任務(wù)完成庄呈,避免數(shù)據(jù)競爭等問題蜕煌。 dispatch_barrier_async 函數(shù)會等待追加到Concurrent Dispatch Queue并行隊列中的操作全部執(zhí)行完之后,然后再執(zhí)行 dispatch_barrier_async 函數(shù)追加的處理抒痒,等 dispatch_barrier_async 追加的處理執(zhí)行結(jié)束之后幌绍,Concurrent Dispatch Queue才恢復(fù)之前的動作繼續(xù)執(zhí)行。
打個比方:比如你們公司周末跟團旅游故响,高速休息站上,司機說:大家都去上廁所颁独,速戰(zhàn)速決彩届,上完廁所就上高速。超大的公共廁所誓酒,大家同時去樟蠕,程序猿很快就結(jié)束了,但程序媛就可能會慢一些靠柑,即使你第一個回來寨辩,司機也不會出發(fā),司機要等待所有人都回來后歼冰,才能出發(fā)靡狞。 dispatch_barrier_async 函數(shù)追加的內(nèi)容就如同 “上完廁所就上高速”這個動作。
舉個栗子:貓8888是設(shè)置的柵欄
通過結(jié)果我們可以看到:貓8888之前的無序的隔嫡,后邊的也是無序的甸怕。在多個并行處理之間插入指定處理后再繼續(xù)多個并行處理。
3腮恩、 Dispatch Group
如果想要在追加到多個Dispatch Queue中的多個處理全部結(jié)束后執(zhí)行結(jié)束處理梢杭,可使用Dispatch Group。
例如:
舉個栗子:
參考:GCD用法詳細介紹
? ? ? ? ? ?招聘一個靠譜的iOS(下)
最后秸滴,哪里不對的地方可以給我留言武契,我會及時改進的,謝謝大家荡含。