剛接觸開發的童鞋,在學習多線程的時候,往往會比較吃力.因為這家伙比較抽象,有的時候較難通過運行代碼直接看到多線程操作應該有的實際效果.和UI相比,多線程部分更注重理解.
所以,希望能通過這個故事,幫助大家更好地理解iOS中的多線程.故事是以GCD為主要實現手段進行展開的.
OK,那廢話不多說,一起走進財富故事匯之屎殼郎老板的公廁生意吧!
屎殼郎老板和它的公廁生意
屎殼郎老板在旅游區開了一間收費公廁,招待南來北往的旅客們。來上廁所的客人,都是跟著各自的旅行團來的。屎殼郎老板要求上廁所的客人一定要排好隊,一個一個來,講文明,懂禮貌,謝絕插隊和隨地大小便等不文明行為。
奇葩的旅客、奇葩的團
屎殼郎老板發現,來它這裡上廁所的旅客,都非常怪異:
明明坑位很多,排隊的人也很多,可是有的時候只有一個坑位被使用,有的時候同時有好多坑位被使用。
為了弄清楚坑位的使用規律,屎殼郎老板對來上廁所的旅客,和他們所在的旅行團進行了調查統計分析。
-- 旅客篇 --
根據旅客的尿意程度,屎殼郎老板把旅客分為兩類:
尿急型
有備無患型
尿急型旅客
一旦前面的坑位沒人,這類旅客就會一頭扎進坑位中。
通過數據分析,屎殼郎老板還發現:
尿急型旅客只認准靠窗的蹲位,別的蹲位一概不去。
有備無患型旅客
這類旅客其實不是很急著上廁所,他們只是看到排隊上廁所的人多,想通過排隊等坑位的時間,來拓展自己的人脈圈的(如此高明的拓展人脈圈手段也是醉了-_-|||)
輪到他們進坑的時候,他們不會一頭扎進去,而是
先勾搭他後面的旅客
“嘿哥們兒,一起啊~”
看到後面的哥們准備動身了,他才動身
屎殼郎老板還發現,這類旅客:
一般會盡最大可能不用靠窗的坑位。
附注:由於尿急型旅客不主動招呼排在他後面的旅客,所以,後面的旅客只有親眼看到尿急旅客已經方便完從坑位出來了,才會選坑進入。
-- 旅行團篇 --
研究完旅客,屎殼郎老板又對旅客們所在的旅行團做了分析和歸類。根據旅行團印發的《關於參團游客排隊上公廁秩序的相關規定》內容進行劃分(這旅行團管的也太寬了吧-_-|||),大致可以分為三大類
寬松型
嚴格型
苛刻型
寬松型
團規:團內旅客盡量用最短的時間解決完上廁所問題,使用哪個坑位不做限制。
嚴格型
團規:不管有沒有空余的坑位,本團內,一次只能有一個旅客在坑位上。
苛刻型
團規:本團內的旅客,只能使用靠窗的那個坑位。
屎殼郎老板很開心,因為有了這兩份資料,他就能提前判斷出,下一次,會有幾個旅客同時進坑,以及他們分別會用幾號坑位。
屎殼郎老板的測試題
OK,屎殼郎老板收集到的情報我們已經掌握了,那麼,屎殼郎老板給大家出了一份測試題,我們一起來試著分析下吧!
題目:
假設這次排隊的旅客有四個:
其中 三個來自名叫“嚴格旅行團”的嚴格型旅行團
另外兩個來自名叫“寬松旅行團”的寬松型團
根據從前到後的順序,他們分別是:
* 小A同學:來自寬松團,有備無患型
* 小B同學:來自寬松團,有備無患型
* 小C同學:來自嚴格團,尿急型
* 小D同學:來自寬松團,有備無患型
* 小E同學:來自嚴格團,尿急型
模擬入坑過程
第一階段
輪到排在最前面的小 A 同學入坑了,由於小 A是個有備無患型的,扭過頭來招呼小 B:“嘿哥們兒~一起啊~”
小 B 同學也興奮的扭過頭招呼小 C:" 嘿哥們,一起啊~"
小 C 已經憋很久了,拔腿就准備往蹲位裡沖。
小 B 看到小 C 准備動身了,自己也整理整理准備動身。
小 A 看小 B 准備動身了,自己馬上動身走向坑位。因為是有備無患型,所以小 A 討厭靠窗的1號蹲位,選擇了2號蹲位。
小 B 動身前也思考了一下,我們團允許多個團員同時入坑。於是小 B 也動身了。有備無患型,討厭靠窗的1號蹲位,2號蹲位又有人了,於是選擇了3號蹲位
雖然便意濃濃,但小 C 還是略一思忖:我們團規定一次只能一個人入坑,前面入坑的兩個都不是我們團的,看來我能入坑。然後看了一眼坑位:我喜歡的靠窗1號坑正好沒人用!然後拔腿奔向了1號坑位。
總結:第一階段同時入坑的有ABC三 位同學,分別使用了2號坑、3號坑和1號坑
第二階段
親眼看見小 C 從蹲位裡面帶幸福的走出來,小 D 知道,輪到自己了。於是招呼小 E 一起入坑
小 E 二話不說低著頭就准備往坑裡沖。小 D 見狀略一思忖:我們團允許多個本團成員一起入坑,雖然之前兩個團員小 A 和小 B 還沒出來(假設小 A 和小B 解決的比較慢),但我還是可以入坑的。 於是動身選坑位
1號坑位雖然沒人,但是小 D不喜歡,2號3號有人了(小 A 小 B 在裡面),所以小 D 選擇了4號坑位
小 E 臨行前也簡單思考了下:我們團沒有人在蹲位中,1號蹲位沒有人。於是小 E 沖向了1號蹲位。
總結:第二階段同時入坑的有 DE 兩位同學,分別使用了4號坑和1號坑。
驗證
OK~分析完成,我們用代碼來驗證下是不是這樣~
代碼們
屎殼郎老板的測試題 - 代碼驗證.png
可以嘗試自己運行下看看結果是不是和我們分析的一樣哦!
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { // 創建名叫“嚴格旅行團”的嚴格型旅行團 dispatch_queue_t seriouslyTeam = dispatch_queue_create("com.azen.xu", DISPATCH_QUEUE_SERIAL); // 創建名叫“寬松旅行團”的寬松型旅行團 dispatch_queue_t relaxingTeam = dispatch_queue_create("com.azen.xu",DISPATCH_QUEUE_CONCURRENT); // 創建寬松團的有備無患型小 A dispatch_async( relaxingTeam, ^{ // 讓小 A 便便的時間長一點 for (int i = 0 ; i <= 1000 ; i++) { NSLog(@"我是小 A,我在便便 -- 完成度 %%%.3f ---%@",i * 0.1,[NSThread currentThread]); } }); // 創建與小 A 相似的小 B dispatch_async( relaxingTeam, ^{ // 讓小 B 便便的時間也長一點 for (int i = 0 ; i <= 1000 ; i++) { NSLog(@"我是小 B,我在也便便 -- 完成度 %%%.3f ---%@",i * 0.1,[NSThread currentThread]); } }); // 創建嚴格團的尿急小 C dispatch_sync(seriouslyTeam, ^{ // 小 C 便的時間短一點 for (int i = 0 ; i <= 10 ; i++) { NSLog(@"我是小 C,我在也便便 -- 完成度 %%%d ---%@",i * 10,[NSThread currentThread]); } }); // 寬松團的有備無患型小 D dispatch_async( relaxingTeam, ^{ // 讓小 D 便便的時間也長一點 for (int i = 0 ; i <= 1000 ; i++) { NSLog(@"我是小 D,我在也便便 -- 完成度 %%%.3f ---%@",i * 0.1,[NSThread currentThread]); } }); // 嚴格團的尿急小 E dispatch_sync( seriouslyTeam, ^{ // 讓小 E 便便的時間也長一點 for (int i = 0 ; i <= 1000 ; i++) { NSLog(@"我是小 E,我在也便便 -- 完成度 %%%.3f ---%@",i * 0.1,[NSThread currentThread]); } }); }
總結
嗯哼~ 故事講完了。沒看明白?不知道這鬼東西有什麼卵用?不妨看看下面的對照表哦:
概念對照表
旅客 對應 任務
尿急型旅客 對應 同步任務
有備無患型旅客 對應 異步任務
旅行團 對應 隊列
寬松型旅行團 對應 並發隊列(Concurrent Dispatch Queue)
嚴格型旅行團 對應 串行隊列(Serial Dispatch Queue)
苛刻型旅行團 對應 主隊列(Main Queue)
蹲位 對應 線程
靠窗蹲位 對應 主線程
(所有涉及 UI 展示方面的任務都要在主線程中執行,所以... 主線程就是靠窗的蹲位啦...)
其他蹲位 對應 子線程
應用
嘗試用多線程知識實現:分 六個任務別打印A、B、C、D、E 、F 六個字母,要求:A打印完後打印 B 和 C(要求BC幾乎同時打印),C 打印完後打印D、E、F( DEF幾乎同時打印)
最後的最後
一個故事並不能將多線程的知識完全講清楚,只是希望,這篇小小的、有點怪誕、槽點滿滿的故事,能帶給大家一點輕松快樂的好心情。會心一笑,然後帶著這份好心情,一起繼續在這個充滿魔法的編程世界裡前行吧~ ^_^
PS. 剛編出來這個故事時候,每次上廁所看到蹲位都忍不住想笑... 不過想到邊排洩邊傻笑可能有點怪怪的...所以還是忍住了= =
PPS. 屎殼郎老板的故事還沒有結束哦!下一篇——《屎殼郎老板的神奇寶貝——蹲位獸》,和大家一起探秘屎殼郎老板公廁的蹲位,順便聊一點runloop的小知識^_^