iOS開發——GCD總結

來源:互聯網
上載者:User

標籤:簡單   time函數   bsp   用法   有用   null   定義   延遲   soa   

  Grand Central Dispatch,簡稱GCD,在非同步執行任務的技術之一。

  一般將應用程式中記述的線程管理用的代碼在系統級中實現,開發人員只需要定義想執行的任務並追加到適當的Dispatch Queue中,GCD就能產生必要的線程並計劃執行任務。這句話用代碼錶示如下:

dispatch_async(queue, ^{

        /*

         * 想要執行的任務

         */

    });

  雖然多線程可以給開發貸來便利,在執行長時間的處理時仍可保證使用者介面的響應效能。但是,如果過多使用多線程,就會消耗大量記憶體,引起大量的環境切換,大幅度降低系統的響應效能。

 

  1、Dispatch Queue的種類:Serial Dispatch Queue和Concurrent Dispatch Queue

  (1)、Serial Dispatch Queue,簡單的理解就是,使用一個線程,按照隊列的規矩,任務排好隊,一個接一個的順序執行;

  (2)、Concurrent Dispatch Queue,簡單的理解就是,XNU核心決定使用的線程數,並根據所需的線程執行處理,雖然也是排隊,但是服務的視窗多了。

 

  2、dispatch_queue_create

  dispatch_queue_create函數的傳回值為表示Dispatch Queue的“dispatch_queue_t類型”,建立如下:

  dispatch_queue_t queue = dispatch_queue_create(<#const char * _Nullable label#>, <#dispatch_queue_attr_t  _Nullable attr#>);

  第一個參數:可以指定queue的名稱,也可以設為NULL,命名推薦使用應用程式ID這種逆序全程網域名稱(FQDN, fully qualified domin name),該名稱在Xcode和Instruments的調試器中作為Disoatch Queue名稱使用,另外,該名稱也出現在應用程式崩潰時所產生的CrashLog中。如果嫌命名麻煩,在這裡設的是NULL,調試的時候,會不會後悔沒有為Dispatch Queue命名,這個就不好說了;

  第二個參數:指定建立Dispatch Queue的種類,可以指定為NULL,預設的是Serial Dispatch Queue,也可以設定為DISPATCH_QUEUE_CONCURRENT,這個產生的就是Concurrent Dispatch Queue。

 

  3、dispatch_release

  儘管有ARC這一通過編譯器自動管理記憶體的優秀技術,但產生的Dispatch Queue必須由程式員負責釋放。

  通過dispatch_queue_create函數產生的Dispatch Queue,在使用結束後通過dispatch_release函數釋放,使用很簡單:dispatch_release(<#object#>);

  看到release,由此可以推測出相應地也存在dispatch_retain函數,即Dispatch Queue也像OC的引用計數式管理記憶體一樣,需要通過dispatch_retain函數和dispatch_release函數的引用計數來管理記憶體。

  拓展問題:一建立Dispatch Queue,然後在dispatch_async函數中追加Block到Dispatch Queue後,立即通過dispatch_release函數釋放,是否可以?

  這樣做完全沒有問題,在dispatch_async函數中追加Block到Dispatch Queue,該Block就通過dispatch_retain函數持有了Dispatch Queue,這時即使立即釋放Dispatch Queue,該Dispatch Queue由於被Block持有而不會被廢棄,因而Block能夠繼續執行,Block執行結束後會釋放Dispatch Queue,這時誰也不持有Dispatch Queue,這時Dispatch Queue才會被廢棄。

 

  4、Main Dispatch Queue/Global Dispatch Queue

  實際上不用特意產生Dispatch Queue,系統也會給我們提供幾個,那就是Main Dispatch Queue和Global Dispatch Queue。

  Main Dispatch Queue,可以理解為系統為我們開啟的主隊列,是在主線程中執行的Dispatch Queue,因為主線程就只有一個,所以Main Dispatch Queue是Serial Dispatch Queue。

  Main Dispatch Queue的擷取方法如下:

  dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
  追加到Main Dispatch Queue的處理,是在主線程的RUNLoop中執行,所以在子線程處理任務時,會將使用者介面的介面更新等一些必須在主線程中執行的處理追加到Main Dispatch Queue中。這與NSObject類的performSelectorOnMainThread這一方法相同。

  Global Dispatch Queue,可以理解為系統為我們開啟的全域隊列,是所有應用程式都能夠使用的Concurrent Dispatch Queue。不用通過dispatch_queue_create函數產生Concurrent Dispatch Queue。只有擷取Global Dispatch Queue就可以使用。

  Global Dispatch Queue的擷取方法如下:

  dispatch_queue_t globalDispatchQueue = dispatch_get_global_queue(<#long identifier#>, <#unsigned long flags#>);

  第一個參數:Global Dispatch Queue的優先順序,Global Dispatch Queue有四個執行優先順序,分別是高優先順序(High Priority)、預設優先順序(Default Priority)、低優先順序(Low Priority)、後台優先順序(Background Priority)。Global Dispatch Queue的執行優先順序作為線程的執行優先順序使用,在向Global Dispatch Queue追加處理時,應選擇與處理內容對應的執行優先順序的Global Dispatch Queue。

  第二個參數:作為保留欄位備用,一般為0。

 

  5、dispatch_after

  在指定時間後執行某個操作,可使用dispatch_after函數來實現。

  dispatch_after函數並不是在指定時間後執行處理,只是在指定時間追加處理到Dispatch Queue。雖然在有嚴格時間要求下使用會出現問題,但在大致時間執行處理,表現還是可以的。使用如下:

  dispatch_after(<#dispatch_time_t when#>, <#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>);

  第一個參數:指定時間用的dispatch_time_t類型的值,該值可用dispatch_time函數或dispatch_walltime函數獲得;

  第二個參數:指定要追加處理的Dispatch Queue;

  第三個參數:指定要執行處理的Block;

  擷取dispatch_time_t方法如下:
  dispatch_time_t time = dispatch_time(<#dispatch_time_t when#>, <#int64_t delta#>);

  第一個參數:指定的開始時間,這個值經常使用DISPATCT_TIME_NOW,這表示現在的時間。

  第二個參數:指定的延遲時間,如果是3秒後的話,這裡應該填,3ull*NSEC_PER_SEC,“ull”是C語言的數值字面量,是顯示表明類型時使用的字串(表示"unsigned long long")。NSEC_PER_SEC這是以秒為單位,NSEC_PER_MSEC這是以毫秒為單位。

 

  6、Dispatch Group

  執行多個任務,全部結束後通知執行某一操作,這樣就需要用到Dispatch Group。

  直接舉個例子,一目瞭然。

    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    dispatch_group_t group = dispatch_group_create();

    // 任務放進 group

    dispatch_group_async(group, queue, ^{

        // 任務1

    });

    dispatch_group_async(group, queue, ^{

        // 任務2

    });

    dispatch_group_async(group, queue, ^{

        // 任務3

    });

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{

        // 任務全部完成後的處理

    });

  三個任務都放進group裡,都執行完後,調用dispatch_group_notify函數,dispatch_group_notify裡面的queue,不管是什麼樣的queue,都沒關係。

  任務結束後的處理,也可以使用dispatch_wait(<#object#>, <#timeout#>);第二個參數為等待的時間,將它設為DISPATCH_TIME_FOREVER,就意味永久等待,只要Dispatch Group的處理尚未結束,就會一直等待。注意:dispatch_group_wait,是會阻塞當前進程的,所以最好不要放在主線程執行,可以將它放到子線程中去。但從這點來看,推薦使用dispatch_group_notify。但是dispatch_group_wait還有一個用法,就是在指定時間後,任務是否執行完畢,傳回值為0,就是任務全部完成,傳回值不為0,就意味著Dispatch Group的某一個任務還在執行中,這個在某些場合還是有用的。

 

  7、dispatch_barrier_async

  在訪問資料庫或檔案時,讀取與讀取操作是可以平行處理,都是讀取和寫入操作是相互衝突的,這個涉及到資料競爭問題,可以使用dispatch_barrier_async和Concurrent Dispatch Queue配合使用,解決這個問題。例子如下:

   dispatch_queue_t queue = dispatch_queue_create("com.hehe.gcd.forBarrier", DISPATCH_QUEUE_CONCURRENT);

   dispatch_async(queue, ^{

        //讀操作

    });

    dispatch_async(queue, ^{

        //讀操作

    });

    dispatch_barrier_async(queue, ^{

        //寫操作

    });

    dispatch_async(queue, ^{

        //讀操作

    });

    dispatch_async(queue, ^{

        //讀操作

    });

 

  為了更高效率的訪問,讀取操作追加到Concurrent Dispatch Queue中,寫入操作放在dispatch_barrier_async裡面,dispatch_barrier_async會等待它前面追加到Concurrent Dispatch Queue上的並存執行的處理全部結束之後,再執行dispatch_barrier_async中追加的處理,等這個寫入操作完成後,才會將它之後的處理加入到Concurrent Dispatch Queue中,繼續執行。

 

  8、dispatch_sync

  dispatch_async:async意味著“非同步”,就是講指定的Block“非同步”的追加到指定的Dispatch Queue中,dispatch_async函數不做任何等待。簡單的說就是,任務直接加到Dispatch Queue中,串列還是平行處理再看Dispatch Queue的設定。

  dispatch_sync:sync意味著“同步”,也就是講指定的Block“同步”的追加到指定的Dispatch Queue中,dispatch_async函數會一直等待。簡單的說就是,一旦調用dispatch_sync函數,處理結束之前,該函數都不會返回,其他的任務要等前一個任務執行完了,才會再加一個任務到Dispatch Queue中。

  dispatch_sync只能在當前線程下串列執行,而且,它不能放在主線程中,只要放在主線程中,就會引起死結。

 

  9、dispatch_apply

  dispatch_apply函數是dispatch_sync和Dispatch Group的關聯API,該函數將指定的Block追加到指定的Dispatch Queue中,並等待全部執行完成。

  dispatch_apply(<#size_t iterations#>, <#dispatch_queue_t  _Nonnull queue#>, <#^(size_t)block#>);

  第一個參數:重複次數。

  第二個參數:追加對象的Dispatch Queue。

  第三個參數:追加的處理,裡面有index。

  由於dispatch_apply函數也與dispatch_sync相同,會等待處理執行結束,因此,推薦在dispatch_async函數中非同步的執行dispatch_apply函數,這樣執行完了,在搞個dispatch_get_main_queue,就可以回主線程做一些更新操作。

 

  10、dispatch_suspend/dispatch_resume

  當追加大量處理到Dispatch Queue後,在處理的過程中,dispatch_suspend是暫停處理,dispatch_resume是恢複繼續處理。

  dispatch_suspend(<#dispatch_object_t  _Nonnull object#>);

  dispatch_resume(<#dispatch_object_t  _Nonnull object#>);

 

iOS開發——GCD總結

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.