Objective-C中GCD

  1. 同步
  2. 異步
  3. 並行
  4. 串行
  5. 任務組
  6. 時間等待

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的執行階層的方法:app

  • 也是經過調用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時)所有結束後(在未所有執行結束前不會讓調用執行的線程掛起等待)執行指定操做的方法(可用於任務間的依賴關係): async

  • 經過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均可以)中,並等待所有處理執行結束的方法:spa

  • 經過調用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 I/O處理(略)

往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 *_aString=@"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死鎖了
    • });
    • });
    • });
相關文章
相關標籤/搜索