沒錯就是解毒
前言
GCD做為iOS開發(fā)中多線程管理的重要幫手折砸。起初我只能說是用過看疗,但是并沒有較為仔細的了解它。最近又一次重新梳理了一下睦授,雖然目前來看两芳,還存在一些問題,無法解釋去枷。但還是先做個筆記怖辆,與大家分享下是复。同時,希望大家也能一起探索或者幫忙解答下這些問題:]
<p>
一些概念
首先竖螃,我們來解讀一些基本的概念淑廊。在多線程開發(fā)中我們經(jīng)常會遇到很多的名詞,一時間也沒辦法分清他們到底是什么意思特咆。所以我在這里做個簡單的整理
并行 和 并發(fā)
并發(fā): 統(tǒng)一執(zhí)行很多任務季惩,表面上同時發(fā)生,但是實際上是計算機分時處理的結(jié)果腻格,即CPU在不同的任務之間進行切換蜀备,執(zhí)行一段時間后切換到另一個線程。
并行:真正意義上的同時執(zhí)行任務荒叶。
兩者的區(qū)別實際上用一張圖就能很好的說明
同步 和 異步
同步:等操作完成才返回
異步:直接返回
串行隊列 和 并發(fā)隊列
串行隊列:一次只執(zhí)行一個任務
并發(fā)隊列: 一次執(zhí)行多個任務
這里我們需要說明的是碾阁,無論是并發(fā)隊列還是并行隊列,他們都是FIFO的些楣,也就是說先添加到隊列中的任務會先被執(zhí)行脂凶,但是對于并發(fā)隊列而言,我們不能保證執(zhí)行完成時的順序愁茁。另外蚕钦,在一些博文中會將Concurrent Queue翻譯為 并行隊列,個人認為并不是很嚴謹鹅很。首先是因為Concurrent 本意就是并發(fā)嘶居,并且如果使用并發(fā)這個名詞,對于一些初學者來講可能會產(chǎn)生誤導促煮,隊列中的任務到底是并發(fā)執(zhí)行還是并行執(zhí)行的呢邮屁?
進程 和 線程
進程:是操作系統(tǒng)對于正在運行的程序的一種抽象,在系統(tǒng)上可以同時運行多個進程菠齿,而每個進程都好像在獨立使用硬件
線程:一個進程實際上可以由多個線程的執(zhí)行單元組成佑吝,每個線程都在進程的上下文中,共享同樣的代碼和全局數(shù)據(jù)
進程绳匀、線程和應用程序的關(guān)系:進程為應用程序開辟內(nèi)存空間芋忿,而線程執(zhí)行應用程序代碼
進程和線程的關(guān)系:進程由線程組成、一個進程理論上可以有很多的線程疾棵,但至少有一個主線程戈钢。
死鎖
死鎖: 兩個或多個線程相互等待而導致任何一個線程都不能執(zhí)行。
概念匯總
關(guān)于一些問題的想法
我們經(jīng)常會看到以下代碼
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//[self do something];
});
這段代碼表示我們“開啟一個異步線程是尔,在全局隊列中執(zhí)行”
那么我們?nèi)绻覀儗?code>dispatch_get_global_queue()函數(shù)改為dispatch_get_main_queue()
就會說我們在主線程上做處理事務殉了,而事實上我們使用這個函數(shù)創(chuàng)建或得到的是一個隊列而非線程。
更準確的說嗜历,我認為压状,我們使用GCD的時候應該是面向隊列痛阻,而不是線程。在很多的博客中都會使用NSLog(@"current thread is %@", [NSThread currentThread])
這段代碼來打印當前的線程,然后告訴你說我們在XX線程上執(zhí)行了代碼抱慌。的確,這樣的方式更加直接的說明了問題蔚携。但是就像我之前提到的房维,開發(fā)者應該面向的是隊列而不是線程,所以這只是輔助說明的一種方式每窖。
OK帮掉,接下來我們討論下dispatch_async和dispatch_sync函數(shù)都干了些什么。開始我以為他們是創(chuàng)建線程用的窒典,就如一些的博文中會講到蟆炊,“每執(zhí)行一次任務的時候,dispatch_async總會為我們開辟一個新的線程”
真的是這樣嗎瀑志?
我在文檔里看到如下說明
dispatch_sync
Submits a block object for execution on a dispatch queue and waits until that block completes.
Submits a block to a dispatch queue for synchronous execution. Unlike dispatch_async, this function does not return until the block has finished. Calling this function and targeting the current queue results in deadlock
dispatch_async
Submits a block for asynchronous execution on a dispatch queue and returns immediately.
This function is the fundamental mechanism for submitting blocks to a dispatch queue. Calls to this function always return immediately after the block has been submitted and never wait for the block to be invoked. The target queue determines whether the block is invoked serially or concurrently with respect to other blocks submitted to that same queue. Independent serial queues are processed concurrently with respect to each other.
這里我認為涩搓,這兩個函數(shù)只是用于提交任務或者說block的。他們唯一的區(qū)別是會不會等待任務完成劈猪。對于dispatch_sync
而言昧甘,他會提交任務,同時阻塞當前的線程直到任務執(zhí)行完成才會返回战得。 dispatch_async
則會在提交任務之后直接返回充边,不阻塞和等待。如此一來常侦,真正和與線程相關(guān)的就可能是隊列了浇冰。
另一種視角
前面提到的在GCD中我們只是面向隊列和任務。隊列包括串行隊列和并發(fā)隊列聋亡,而任務提交是同步或者異步的湖饱。那么我們就來看下這些概念排列組合后的場景。
同步提交 + 串行隊列
說明:在調(diào)用dispatch_sync方法的時候我們指定了添加任務的隊列和任務(block)杀捻。那么該方法就會提交該任務到串行隊列中井厌,然后然后阻塞線程,等待任務完成之后再返回致讥。對于串行隊列仅仆,前面的概念解釋里已經(jīng)說過了,任務一個接一個執(zhí)行垢袱。
異步提交 + 并發(fā)隊列
說明:異步提交的時候墓拜,dispatch_async函數(shù)提交然后直接返回。區(qū)別是并發(fā)隊列會一次執(zhí)行多個任務请契。
同步提交 + 并發(fā)隊列
異步提交 + 串行隊列
代碼部分
我們在從代碼部分去理解同步和異步的問題
左側(cè)兩段輸出咳榜,我們可以看到夏醉,都是同步提交,無論是提交到串行隊列還是并發(fā)隊列涌韩,執(zhí)行的順序都是一樣的畔柔。并且提交任務前后的代碼的順序都是依次執(zhí)行的。
在看右側(cè)部分臣樱,由于異步提交后直接返回不等待執(zhí)行完成靶擦。所以任務提交前后的代碼會先于任務中的代碼執(zhí)行。
接下來雇毫,我們在從代碼的角度去理解串行隊列和并發(fā)隊列
并發(fā)
在同樣是異步的前提下玄捕,任務前后的代碼都先于任務執(zhí)行了(當然這并不是絕對的)。我們看到在串行隊列中棚放,執(zhí)行任務的線程不在主線程中枚粘,但是他們都是在一個線程中去處理。也正因為任務前后的代碼執(zhí)行和任務代碼執(zhí)行的線程不同飘蚯,所以我們并不能保證任務部分的代碼和任務后的代碼的執(zhí)行先后性赌结。因此會出現(xiàn)任務代碼先執(zhí)行,在執(zhí)行過程又出現(xiàn)任務后的打印輸出孝冒。
同樣是同步提交的情況下柬姚,兩個輸出完全一致。串行隊列同步提交的情況我們可以理解庄涡,因為它一次只執(zhí)行一個任務量承,所以線程號是一樣的。但是穴店,并發(fā)隊列的情況下撕捍,該怎么理解?其實也很簡單泣洞,因為他是同步提交忧风,需要等到當前任務完成后返回再進行后續(xù)的操作,所以即使是并發(fā)的隊列球凰,我們看到的效果還是和串行一樣狮腿。
遺留的問題
首先很感謝你能看到這里,聽我瞎扯那么多呕诉。
以上是我個人的理解缘厢,感覺與一些博文中的思想有些出入,所有我也不是很確定甩挫。我僅以
我看到的為參考贴硫,并提出自己的理解。
目前還有以下問題暫時沒有想通:
1)隊列和線程的關(guān)系
從文檔中有看到系統(tǒng)實際上有維持一個線程池伊者,但是沒有說清隊列和它有什么具體的關(guān)系英遭。
2)隊列和主線程的關(guān)系
如下圖间护,同樣是在主線程中執(zhí)行,但是如果將這個queue改成main queue時就會報錯挖诸。
歸根結(jié)底還是沒有理清線程和隊列的關(guān)系汁尺,或者說是主線,隊列税灌,其它線程這三者的關(guān)系均函。
如果覺得我的想法有問題的同學亿虽,請幫忙指正菱涤,萬分感謝。
如果覺得我理解有道理的同學洛勉,希望能一起探討一下遺留的問題粘秆,共同完善知識體系:]
最后放上源代碼
GCD解毒Demo