1. 程式人生 > >iOS多執行緒的初步研究(八)-- dispatch佇列

iOS多執行緒的初步研究(八)-- dispatch佇列

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佇列

GCD程式設計的核心就是dispatch佇列,dispatch block的執行最終都會放進某個佇列中去進行,它類似NSOperationQueue但更復雜也更強大,並且可以巢狀使用。所以說,結合block實現的GCD,把函式閉包(Closure)的特性發揮得淋漓盡致。 dispatch佇列的生成可以有這

iOS 執行初步研究-NSThread

對於多執行緒的開發,iOS系統提供了多種不同的介面,先談談iOS多執行緒最基礎方面的使用。產生執行緒的方式姑且分兩類,一類是顯式呼叫,另一類是隱式呼叫。 一、顯示呼叫的類為NSThread。一般構造NSThread的執行緒物件可通過兩種方式: 1. 初始化執行緒主方法: [NSThread deta

java執行快速入門

設定執行緒優先順序:join() package com.cppdy; class MyThreadA extends Thread{ MyThreadB b; public MyThreadA(MyThreadB b) { this.b=b; }

Linux執行基礎學習私有資料

/*============================================================================ // Name : thread_privateData.cpp // Author : Ryan // Version

iOS執行初步研究-- dispatch同步

一、dispatch組(dispatch group) 1. 建立dispatch組 dispatch_group_t group = dispatch_group_create();  2. 啟動dispatch佇列中的block關聯到group中 dispatch_group_async(group,

iOS執行初步研究dispatch

dispatch源(dispatch source)和RunLoop源概念上有些類似的地方,而且使用起來更簡單。要很好地理解dispatch源,其實把它看成一種特別的生產消費模式。 dispatch源

ios執行初步,主執行重新整理UI

去研究一下iOS多執行緒的起因是自己程式裡用了一個等待指示器UIActivityIndicatorView,俗稱小菊花。但是在給頂層ViewController用addsubview加入這個控制元件並使轉動時,螢幕並沒有出現菊花。經過好一番除錯都沒找到原因。去網

iOS 執行使用總結很實用

每次準備開始新的航行,總是要複習一遍演算法啊,多執行緒啊,記憶體管理啊之類的理論和應用知識,這次把他們整理成文件,方便以後的學習和不斷的積累進步。         多執行緒給我留下的是痛苦的記憶,當時在上家創業公司的最後階段,就是被Feature Phone上面的多執行緒方案導致bug叢生,搞的焦頭爛額。  

執行詳解

多執行緒詳解(二) 在正式介紹執行緒建立的第二種方法之前,我們接著多執行緒詳解(一),講一下:對執行緒的記憶體圖、執行緒的狀態,為下面的學習打下基礎,小夥伴們不要急喲!! 一、多執行緒執行的記憶體圖(ps.博主沒有找到合適的畫圖工具,歡迎大神們貢獻啊) class pers

執行詳解

[多執行緒詳解(一)](http://www.neilx.com) 一、概念準備 1、程序 (1)直譯:正在進行中的程式 (2)解釋:執行一個程式時,會在記憶體中為程式開闢空間,這個空間就是一個程序。 (3)注意:一個程序中不可能沒有執行緒,只有有了執行緒才能執行; 程序只

Linux程式設計 程序,執行求解PI圓周率

題目: 連結 多程序: #include <unistd.h> #include <stdio.h> #include <stdlib.h> #define n 100000000.0 int main() { i

執行學習總結

一、多執行緒帶來的問題 (一)活躍性問題 死鎖:兩個執行緒相互等待對方釋放資源 飢餓: 多執行緒併發時優先順序低的執行緒永遠得不到執行;執行緒被永久阻塞在一個等待進入同步塊的狀態;等待的執行緒永遠不被喚醒 活鎖:活鎖指的是任務或者執行者沒有被阻塞,由於某些條件沒有滿足,導致

執行學習總結

一、程序和執行緒的定義 程序:程序是資源(CPU、記憶體等)分配的基本單位,它是程式執行時的一個例項。程式執行時系統就會建立一個程序,併為它分配資源,然後把該程序放入程序就緒佇列,程序排程器選中它的時候就會為它分配CPU時間,程式開始真正執行。 執行緒:執行緒是程式執行時的最小單位,它是程序

java:執行的基礎引入

* 1.什麼是執行緒     * 執行緒是程式執行的一條路徑, 一個程序中可以包含多條執行緒     * 多執行緒併發執行可以提高程式的效率, 可以同時完成多項工作* 2.多執行緒的應用場景     * 紅

java執行快速入門

通過匿名內部類的方法建立多執行緒 package com.cppdy; //通過匿名內部類的方法建立多執行緒 public class ThreadDemo2 { public static void main(String[] args) { new Thread(ne

java執行快速入門

多執行緒應用例項(批量傳送簡訊) 1、建立實體類 package com.cppdy; public class UserEntity { private int id; private String name; public int g

java執行快速入門

什麼是守護執行緒   守護執行緒是為使用者執行緒服務的這麼一個執行緒,主執行緒結束,守護執行緒也結束 package com.cppdy; class MyThread3 extends Thread{ @Override public void run() {

java執行快速入門

多執行緒安全問題(賣火車票案例) package com.cppdy; class MyThread5 implements Runnable{ private Integer ticketCount=100; @Override public void run() {

java執行快速入門十三

死鎖產生的原因(必須有兩個執行緒、必須有多個鎖、鎖之間必須有引用的過程) package com.cppdy; class MyThread9 implements Runnable { private Integer ticketCount = 100; private Obje

Java——執行基本使用 執行組和執行池的使用,工廠設計模式的使用

1.執行緒組的概述和使用 Java中使用ThreadGroup來表示執行緒組,它可以對一批執行緒進行分類管理,Java允許程式直接對執行緒組進行控制。            &n