iOS多線程的初步研究(八)-- dispatch隊列

來源:互聯網
上載者:User

標籤:

GCD編程的核心就是dispatch隊列,dispatch block的執行最終都會放進某個隊列中去進行,它類似NSOperationQueue但更複雜也更強大,並且可以嵌套使用。所以說,結合block實現的GCD,把函數閉包(Closure)的特性發揮得淋漓盡致。 dispatch隊列的產生可以有這幾種方式:

 1. dispatch_queue_t queue = dispatch_queue_create("com.dispatch.serial", DISPATCH_QUEUE_SERIAL); //產生一個串列隊列,隊列中的block按照先進先出(FIFO)的順序去執行,實際上為單線程執行。第一個參數是隊列的名稱,在偵錯工具時會非常有用,所有盡量不要重名了。

 2. dispatch_queue_t queue = dispatch_queue_create("com.dispatch.concurrent", DISPATCH_QUEUE_CONCURRENT); //產生一個並發執行隊列,block被分發到多個線程去執行

 3. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //獲得程式進程預設產生的並發隊列,可設定優先順序來選擇高、中、低三個優先順序隊列。由於是系統預設產生的,所以無法調用dispatch_resume()和dispatch_suspend()來控制執行繼續或中斷。

需要注意的是,三個隊列不代表三個線程,可能會有更多的線程。並發隊列可以根據實際情況來自動產生合理的線程數,也可理解為dispatch隊列實現了一個線程池的管理,對於程式邏輯是透明的。 

官網文檔解釋說共有三個並發隊列,但實際還有一個更低優先順序的隊列,設定優先權為DISPATCH_QUEUE_PRIORITY_BACKGROUND。Xcode調試時可以觀察到正在使用的各個dispatch隊列。 

 4. dispatch_queue_t queue = dispatch_get_main_queue(); //獲得主線程的dispatch隊列,實際是一個串列隊列。同樣無法控制主線程dispatch隊列的執行繼續或中斷。 接下來我們可以使用dispatch_async或dispatch_sync函數來載入需要啟動並執行block。 

 dispatch_async(queue, ^{   //block具體代碼 }); //非同步執行block,函數立即返回 

 dispatch_sync(queue, ^{   //block具體代碼 }); //同步執行block,函數不返回,一直等到block執行完畢。編譯器會根據實際情況最佳化代碼,所以有時候你會發現block其實還在當前線程上執行,並沒用產生新線程。 實際編程經驗告訴我們,儘可能避免使用dispatch_sync,嵌套使用時還容易引起程式死結。 如果queue1是一個串列隊列的話,這段代碼立即產生死結:  

 dispatch_sync(queue1, ^{      

dispatch_sync(queue1, ^{     ......   });   

......  

}); 

 不妨思考下,為什麼下面代碼在主線程中執行會死結: 

 dispatch_sync(dispatch_get_main_queue(), ^{   ...... }); 

 那實際運用中,一般可以用dispatch這樣來寫,常見的網路請求資料多線程執行模型: dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{   

//子線程中開始網路請求資料   

//更新資料模型   

dispatch_sync(dispatch_get_main_queue(), ^{     

//在主線程中更新UI代碼   

}); 

 }); 程式的後台運行和UI更新代碼緊湊,代碼邏輯一目瞭然。 

 dispatch隊列是安全執行緒的,可以利用串列隊列實現鎖的功能。比如多線程寫同一資料庫,需要保持寫入的順序和每次寫入的完整性,簡單地利用串列隊列即可實現: 

 dispatch_queue_t queue1 = dispatch_queue_create("com.dispatch.writedb", DISPATCH_QUEUE_SERIAL); 

 - (void)writeDB:(NSData *)data {   

dispatch_async(queue1, ^{     

//write database   

}); 

 } 

 下一次調用writeDB:必須等到上次調用完成後才能進行,保證writeDB:方法是安全執行緒的。 

 dispatch隊列還實現其它一些常用函數,包括: 

 void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t)); //重複執行block,需要注意的是這個方法是同步返回,也就是說等到所有block執行完畢才返回,如需非同步返回則嵌套在dispatch_async中來使用。多個block的運行是否並發或串列執行也依賴queue的是否並發或串列。 

 void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block); //這個函數可以設定同步執行的block,它會等到在它排入佇列之前的block執行完畢後,才開始執行。在它之後排入佇列的block,則等到這個block執行完畢後才開始執行。 

 void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block); //同上,除了它是同步返回函數 

void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block); //順延強制block 最後再來看看dispatch隊列的一個很有特色的函數: 

void dispatch_set_target_queue(dispatch_object_t object, dispatch_queue_t queue); 它會把需要執行的任務對象指定到不同的隊列中去處理,這個任務對象可以是dispatch隊列,也可以是dispatch源(以後博文會介紹)。而且這個過程可以是動態,可以實現隊列的動態調度管理等等。比如說有兩個隊列dispatchA和dispatchB,這時把dispatchA指派到dispatchB:

 dispatch_set_target_queue(dispatchA, dispatchB); 

那麼dispatchA上還未啟動並執行block會在dispatchB上運行。

這時如果暫停dispatchA運行: 

 dispatch_suspend(dispatchA); 

則只會暫停dispatchA上原來的block的執行,dispatchB的block則不受影響。而如果暫停dispatchB的運行,則會暫停dispatchA的運行。 這裡只簡單舉個例子,說明dispatch隊列啟動並執行靈活性,在實際應用中你會逐步發掘出它的潛力。 dispatch隊列不支援cancel(取消),沒有實現dispatch_cancel()函數,不像NSOperationQueue,不得不說這是個小小的缺憾。

iOS多線程的初步研究(八)-- dispatch隊列

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.