標籤:
- 同步
- 非同步
- 並行
- 串列
- 工作群組
- 時間等待
Dispatch Queue有兩種:
- 1.Serial Dispatch Queue,串列Queue,按隊列順序每次只能執行一個該線程中追加的任務(可通過建立多個串列queue實現並存執行任務(會降低效能))
- 串列queue可解決多個線程更新相同資源導致資料競爭的問題,讓操作該資源的任務放在同一個串列queue中執行即可
- 2.Concurrent Dispatch Queue,並行Queue,該線程中追加的任務可同時執行
擷取Dispatch Queue(dispatch_queue_t類型)對象有兩種方法:
- 1.通過C函數dispatch_queue_create("queueName",NULL);
- 當第二個參數為NULL時,建立的queue為串列queue
- 當第二個參數為DISPATCH_QUEUE_CONCURRENT宏時,建立的queue為並行queue
- dispatch_queue_carete(或其他GCD API中包含create的函數產生的對象)產生的queue需要自己調用dispatch_release(dispatch_queue_t變數)釋放
- dispatch_async(queue變數,^{往queue中追加的任務體block})函數會讓block持有該queue,所以可以在該函數後即時調用dispatch_release(queue變數)函數釋放queue,block執行完後ARC會主動調用dispatch_release(queue變數)函數釋放queue,
- dispatch_retain函數可讓變數持有queue
- 2.通過擷取系統標準提供的Main Dispatch Queue(主線程,串列)或Global Dispatch Queue(並行,有4個執行優先順序:高DISPATCH_QUEUE_PRIORITY_HIGH,預設DISPATCH_QUEUE_PRIORITY_DEFAULT,低DISPATCH_QUEUE_PRIORITY_LOW,後台DISPATCH_QUEUE_PRIORITY_BACKGROUND)
- 擷取Main Dispatch Queue如:dispatch_queue_t mainDispatchQueue=dispatch_get_main_queue();
- 擷取Global Dispatch Queue如:dispatch_queue_t globalDispatchQueue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
- 第一個參數為指定該queue的執行優先順序
變更由dispatch_queue_create函數產生的dispatch_queue_t對象的執行優先順序的方法:
- 通過調用dispatch_set_target_queue(需變更的queue物件變數,要變更成該queue一樣優先順序的queue物件變數)函數
- 眾queue中,只有Global Dispatch Queue可以在擷取時直接指定優先順序,所以dispatch_set_target_queue函數第二個參數可以以Global Dispatch Queue物件變數作為入參去變更第一個參數的queue執行優先順序
限制Dispatch Queue的執行階層的方法:
- 也是通過調用dispatch_set_target_queue(一般是限制串列目標queue1,在限制對象為串列queue2)函數
想在指定時間後把block體任務追加到線程中(指定時間執行任務,也不一定絕對是指定時間後就執行該任務,因為只是指定時間後把任務加到線程中,可能線程還有別的事情做而延遲)的方法:
- 通過調用dispatch_after(dispatch_time_t物件變數,dispatch_queue_t物件變數,^{追加的任務block體})函數
- 第一個參數通過dispatch_time(開始時間如DISPATCH_TIME_NOW,延遲多長時間如3ull*NSEC_PER_SEC)函數擷取dispatch_time_t對象
- dispatch_time(,)函數通常使用者計算相對時間,還有一個dispatch_walltime()函數用於擷取絕對時間(略)
想在多個處理(使用並行queue或同時執行多個串列queue時)全部結束後(在未全部執行結束前不會讓調用執行的線程掛起等待)執行指定操作的方法(可用於任務間的依賴關係):
- 通過Dispatch Group工作群組來追加管理眾任務,具體做法:
- 1.往線程追加block體任務時指定該任務所屬工作群組(各任務block體所追加到的線程不一定需要在同一條線程中,但是需要是同一個工作群組中),通過調用dispatch_group_async(dispatch_grooup_t物件變數,任務追加到的執行的線程queue,^{block任務體})函數多次調用多次追加任務到工作群組中
- 第一個參數通過dispatch_group_create()函數擷取dispatch_group_t對象
- 2.然後通過調用dispatch_group_notify(dispatch_grooup_t物件變數,結束任務執行的線程queue不一定是和工作群組中的其他任務線程一樣,^{block任務體})函數追加工作群組中全部任務執行完後的任務
- 3.最後要釋放由dispatch_group_create()函數擷取dispatch_group_t對象,通過調用dispatch_release(dispatch_group_t物件變數)釋放
想等待工作群組中各任務全部任務執行完畢的方法(在未全部執行結束前會讓調用執行的線程掛起等待)
通過Dispatch Group工作群組來追加管理眾任務,具體做法:
- 1.往線程追加block體任務時指定該任務所屬工作群組,通過調用dispatch_group_async(dispatch_grooup_t物件變數,任務追加到的執行的線程queue,^{block任務體})函數多次調用多次追加任務到工作群組中
- 第一個參數通過dispatch_group_create()函數擷取dispatch_group_t對象
- 2.然後通過調用dispatch_group_wait(dispatch_grooup_t物件變數,dispatch_time_t物件變數等待時間或宏DISPATCH_TIME_FOREVER永遠等)函數等待工作群組中任務執行完畢(中途不能取消)
- dispatch_group_wait(,)函數傳回值==0代表等待時間內工作群組中的任務全部執行完畢,不然就是超過等待的時間後工作群組中的某一個處理還在執行中
- 調用dispatch_group_wait(,)函數的線程會在調用dispatch_group_wait(,)後便開始停止,經過等待時間後或工作群組中任務全部執行完畢後才繼續往下執行
- 3.最後要釋放由dispatch_group_create()函數擷取dispatch_group_t對象,通過調用dispatch_release(dispatch_group_t物件變數)釋放
想讀取檔案或操作資料庫時更高效率不單止所有操作僅交給一條串列線程負責,而是所有讀寫操作並存執行,寫入操作保證在任一個讀取處理沒有執行狀態下執行,並且執行寫入操作未結束前讀取操作不可執行,高效有效處理資源競爭問題:
- 通過調用dispatch_barrier_async/dispatch_barrier_sync函數結合dispatch_queue_create函數產生的並行queue一起使用實現,欄柵追加也就是dispatch_barrier_async/dispatch_barrier_sync只針對並行queue使用,具體做法:
- 1.dispatch_queue_create(,)函數產生並行queue
- 2.需要讀取時調用dispatch_async(並行queue,^{讀取任務block體})往並行queue中追加讀取操作
- 3.在需要寫入操作時,調用dispatch_barrier_async/dispatch_barrier_sync(與讀取操作同一條並行queue,^{寫入任務block體})函數
- 4.需要讀取時調用dispatch_async(並行queue,^{讀取任務block體})往並行queue中追加讀取操作
- (原理:並行隊列如果發現接下來要處理的任務block體是由欄柵方式追加的,那麼就一直等當前這並發線程中已經正在並發執行著的任務塊都執行完,才單獨執行這個欄柵任務block體,等這個欄柵塊執行完後才再去並發執行該並發線程中剩餘的任務體)
想按指定的次數將指定的任務block體追加到指定的dispatch_queue_t(並行或串列的queue都可以)中,並等待全部處理執行結束的方法:
- 通過調用dispatch_apply(指定的追加次數,指定的並行線程,^(size_t index){指定的任務block體})函數實現
- 當執行調用該函數的線程調用了該函數後,將會等待這批次的任務體執行完才往下執行。因此調用該函數的線程一半為子線程並且是在非同步追加到該子線程的任務block體中調用
- 不在子線程調用會卡介面,不是在非同步追加的任務block體中調用的話會導致死結
當線程執行大量操作想掛起線程或者恢複線程的方法:
- 通過調用dispatch_suspend(dispatch_queue_t物件變數)函數可掛起指定的線程
- 通過調用dispatch_resume(dispatch_queue_t物件變數)函數可恢複指定線程繼續執行任務
想保證在引用程式執行期間只執行一次指定處理的方法:
- 通過調用dispatch_once(&dispatch_once_t物件變數,^{指定處理的block體})函數實現
- 其中第一個參數dispatch_once_t物件變數需要是靜態,如直接static dispatch_once_t token;把&token傳入第一個參數即可
- 通常用於建立單例類,如下文法:
- +(id)sharedInstance{
- static MyObject *myObjectManager=nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken,^{
- myObjectManager=[[self alloc]init];
- });
- return myObjectManager;
- }
想進行更細粒度的排他控制的方法:
- 通過Dispathc Semaphore處理(略)
想提高檔案讀取速度的方法:
往Dispatch Queue追加任務有兩種方式:
- 1.非同步追加,調用C函數dispatch_async(dispatch_queue_t類型的queue變數,dispatch_block_t類型的block體^{往queue中追加的任務體block})
- 任務追加到的線程不會等待所追加的任務block體執行結束
- 2.同步追加,調用C函數dispatch_sync(dispatch_queue_t類型的queue變數,dispatch_block_t類型的block體^{往queue中追加的任務體block})
- 任務追加到的線程會一直等待所追加的任務block體執行完成,是簡易版的dispatch_group_wait函數
- 同步追加容易引起死結,如往主線程同步追加任務,因為代碼執行時,主線程在執行往主線程同步追加任務,所以同步追加的任務主線程永遠執行不到,又因是同步追加,所以主線程一直在等待追加的任務執行完畢,
- 導致死結,亦即無論何時,都不能往主線程或主線程執行的任務體中同步追加任務,或者把任務體同步追加到的線程永遠不能是調用追加函數也就是調用dispatch_sync(,)函數時的線程及其線程的外部線程(見一下死結例子)
- 需同步等待例子如:
- 有一條線程比如是主線程執行下面的代碼
- NSString *[email protected]"XXXXX";
- -(NSString *)getaString{
- dispatch_queue_t myQueue=dispatch_queue_creat("handleAStringQueue",NULL);
- __block NSString *aString;//為解決多線程競爭使用_aString成員變數,所以對_aString操作都需放handleAStringQueue串列queue中操作,而在queue中不能直接返回_aString成員對象,因為在block中return只是block的傳回值,所以需要聲明一個替換變數
- dispatch_sync(myQueue,^{aString=_aString});//主線程執行到這裡的時候,由於是同步把block任務追加到myQueue中處理執行,所以主線程會掛起直到myQueue線程把追加的block任務體執行完才往下執行
- return aString;//主線程執行到這裡的時候由於上面是同步執行,所以block任務體一定已經執行完,所以aString已經被賦值,可以返回出去了。如果上面是非同步追加任務的話,那麼主線程會把block任務體追加到myQueue中,不等任務體給aString賦值馬上執行return語句,這樣是達不到原意的。
- }
- 導致死結例子如:(表層死結)
- dispatch_sync(dispatch_get_main_queue(),^{
- NSLog(@"content...");
- });
- 如果以上代碼是在主線程運行,就會導致死結。
- 導致死結例子如:(深層死結)
- dispatch_queue_t queueA=dispathc_queue_create("queueA Name",NULL);
- dispatch_queue_t queueB=dispatch_queue_create("queueB Name",NULL);
- //儘管是在另線程調用以下代碼:
- dispatch_sync(queueA,^{//在queueA中執行以下代碼
- dispatch_sync(queueB,^{//queueA等待queueB執行以下代碼
- dispatch_sync(queueA,^{//queueB等待queueA執行以下代碼
- NSLog(@"content...");//queueA永遠執行不到這裡,因為queueA上面同步等待掛起了,所以queueA死結了
- });
- });
- });
Objective-C中GCD