Objective-C高階程式設計:iOS與OS X多執行緒和記憶體管理
這篇文章主要給大家講解一下GCD的平時不太常用的API,以及文末會貼出GCD定時器的一個小例子。
需要學習的朋友可以通過網盤免費下載pdf版 (先點選普通下載-----再選擇普通使用者就能免費下載了)http://putpan.com/fs/cy1i1beebn7s0h4u9/
1.GCD的API
1.1 Dispatch Queue
要談GCD,就一定要了解Dispatch Queue
(執行處理的等待佇列)。
Dispatch Queue
按照追加的順序(先進先出FIFO,First-In-First-Out)執行處理。
另外在執行處理是存在兩種Dispatch Queue
,一種是等待現在執行中處理的Serial Dispatch Queue
Concurrent Dispatch Queue
。
1.2 dispatch_queue_create
由於平時在使用時,我們大部分都是使用系統提供的Main Dispatch Queue
和Global Dispatch Queue
。
所以關於dispatch_queue_create
API,這裡只說兩點:
- 通過
dispatch_queue_create
函式生成的Dispatch Queue
在使用結束後要通過dispatch_release
- 如果生成過多的執行緒,就會消耗大量記憶體,大幅度降低系統的響應效能。而使用系統提供的
Global Dispatch Queue
則不用擔心這個問題。所以除非必要,其他情況建議使用系統提供的Dispatch Queue
。
1.3 dispatch_set_target_queue
使用dispatch_queue_create
函式生成的Dispatch Queue
,都使用的是與系統提供的Global Dispatch Queue
的預設優先順序相同的優先順序。而要變更生成的執行優先順序的話就要使用dispatch_set_target_queue
函式。
在後臺執行動作處理的Serial Dispatch Queue
dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.example.gcd.mySerialDispatchQueue", NULL);
dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); dispatch_set_target_queue(mySerialDispatchQueue, globalDispatchQueueBackground);
1.3 dispatch_after
dispatch_after
這裡只說一點,dispatch_after
函式並不是在指定時間後執行處理,而只是在指定時間追加處理到Dispatch Queue
。
因為Main Dispatch Queue
在主執行緒的RunLoop
中執行,所以在比如每隔1/60秒執行的RunLoop
中,Block最快在 3 秒後執行,最慢在 3 秒 + 1/60 秒後執行,並且在Main Dispatch Queue
有大量處理追加或主執行緒的處理本身有延遲時,這個時間會更長。
所以該函式在有嚴格時間要求的情況下使用會出現問題,但是隻是想大致延遲執行處理,該函式是非常有效的。
1.4 dispatch_barrier_async
在訪問資料庫或檔案時,使用多執行緒可能會產生資料競爭的問題,當然使用Serial Dispatch Queue
可避免資料競爭。
但是如果讀取處理只是與讀取處理並行執行,那麼多個並行執行就不會發生問題。也就是說為了高效率的進行訪問,讀取處理追加到Concurrent Dispatch Queue
,寫入處理在任一讀取處理沒有執行的狀態下,追加到Serial Dispatch Queue
中即可(在寫入處理結束之前,讀取處理不可執行)。
使用dispatch_barrier_async
便可解決這個問題。dispatch_barrier_async
函式會等待追加到Concurrent Dispatch Queue
上的並行執行的處理全部結束後,再將制定的處理追加到該Concurrent Dispatch Queue
中。然後在由dispatch_barrier_async
函式追加的處理執行完畢後,Concurrent Dispatch Queue
才恢復為一般的動作,追加到該Concurrent Dispatch Queue
的處理又開始並行執行。
dispatch_async(queue, blk0_for_reading);
dispatch_async(queue, blk1_for_reading);
dispatch_async(queue, blk2_for_reading);
dispatch_async(queue, blk3_for_reading);
dispatch_barrier_async(queue, blk_for_writing); dispatch_async(queue, blk4_for_reading); dispatch_async(queue, blk5_for_reading); dispatch_async(queue, blk6_for_reading); dispatch_async(queue, blk7_for_reading);
如上所示,使用方法非常簡單。僅使用dispatch_barrier_async
函式代替dispatch_async
函式即可。
1.5 dispatch_apply
dispatch_apply
函式是dispatch_sync
函式和Dispatch Group
的關聯API。該函式按指定的次數將指定的Block追加到指定的Dispatch Queue
中,並等待全部處理執行結束。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10, queue, ^(size_t index) { NSLog(@"%zu", index); }); NSLog(@"done");
例如,該原始碼的執行結果為:
4
1
0
3
5
2
6
8
9
7
done
因為在Global Dispatch Queue
中執行處理,所以各個處理的執行時間不定。但是輸出結果中最後的done必定在最後的位置上。這是因為dispatch_apply
函式會等待全部處理執行結束。
1.6 Dispatch I/O
大家可能想過,在讀取較大檔案時,如果將檔案分成合適的大小並使用Global Dispatch Queue
並列讀取的話,應該會比一般的讀取速度快不少。能實現這一功能的就是Dispatch I/O
和Dispatch Data
。
如果想提高檔案讀取速度,可以嘗試使用Dispatch I/O
。
1.7 Dispatch Source
GCD中出了主要的Dispatch Queue
外,還有不太引人注目的Dispatch Source
。它是BSD系核心慣有功能kqueue
的包裝。
kqueue
是在XNU核心中發生各種事件時,在應用程式程式設計方執行處理的技術。其CPU負荷非常小,儘量不佔用資源。kqueue
可以說是應用程式處理XNU核心中發生的各種事件的方法中最優秀的一種。
Dispatch Source
可以處理一下事件。
在使用NSTimer做定時器的時候,大家應該都知道如果使用不當,會出現記憶體洩漏的問題。
而如果作為一個封裝的元件來說,就需要將NSTimer屬性暴露出來,在控制器銷燬時,呼叫NSTimer的invalidate方法。如果忘記的話就會記憶體洩漏!
需要IT程式設計經典書籍資源大合集百度網盤連結的加qq 2057904338,不需要的也可以加喲,本人python全棧工程獅一枚,要諮詢python或者IT行業的朋友可以相互探討學習下,就當交個朋友吧!