App開發流程之使用GCD

来源:http://www.cnblogs.com/ALongWay/archive/2016/09/30/5924076.html
-Advertisement-
Play Games

GCD即為Grand Central Dispatch的縮寫,是一種主要用於非同步處理任務的安全的高性能解決方案。 在此不對比其他非同步處理技術,只記錄GCD的使用及說明。 先記錄一些必要的概念:線程,同步,非同步,並行隊列,串列隊列 線程:程式中任務執行流的最小單元。一個應用程式,一般存在一個進程(擁有 ...


GCD即為Grand Central Dispatch的縮寫,是一種主要用於非同步處理任務的安全的高性能解決方案。

在此不對比其他非同步處理技術,只記錄GCD的使用及說明。

先記錄一些必要的概念:線程,同步,非同步,並行隊列,串列隊列

線程:程式中任務執行流的最小單元。一個應用程式,一般存在一個進程(擁有獨立記憶體空間),而每個進程可以有多個線程,即多個任務執行流,類似於工廠車間的流水線。每個應用程式至少存在一個線程,即為主線程,作為唯一可以控制UI的線程。

同步:主要指多個任務在同一個線程上依次執行。

非同步:主要指多個任務在不同線程上同時執行。

隊列:C語言中的隊列指先進先出(FIFO)的數據結構,與棧的先進後出(FILO)相反。在GCD中分DISPATCH_QUEUE_SERIAL(串列隊列)和DISPATCH_QUEUE_CONCURRENT(並行隊列)。

並行隊列:主要指隊列中多個任務可以同時執行。

串列隊列:主要指隊列中多個任務只能依次執行。

 

逐個記錄重要的方法:

dispatch_queue_t dispatch_get_main_queue(void)

獲取主線程關聯的隊列。主隊列是串列隊列,該隊列中任務都將由主線程執行,UI相關的操作必須加入此隊列。

 

dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags);

獲取全局通用的並行隊列。第一個參數一般指定優先順序,有如下選項:

DISPATCH_QUEUE_PRIORITY_HIGH        

DISPATCH_QUEUE_PRIORITY_DEFAULT    

DISPATCH_QUEUE_PRIORITY_LOW         

DISPATCH_QUEUE_PRIORITY_BACKGROUND

第二個參數,用於標記,一般傳入0即可。

 

dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)

自定義創建一個派發隊列。第一個參數作為描述,例如"newcustomqueue";第二個參數一般指定隊列內任務是串列(DISPATCH_QUEUE_SERIAL)還是並行(DISPATCH_QUEUE_CONCURRENT)類型。

 

void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

將一個block加入隊列,非同步執行。

 

void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

將一個block加入隊列,同步執行。

 

使用和測試以上方法 

定義了幾個隊列:

    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_queue_t customSerialQueue = dispatch_queue_create("customserialqueue", DISPATCH_QUEUE_SERIAL);

    dispatch_queue_t customConcurrentQueue  = dispatch_queue_create("customconcurrentqueue", DISPATCH_QUEUE_CONCURRENT);

使用示例一:

總結:

上述代碼,在同一次運行中,執行了多次,其中兩次截圖如上。

1.主隊列必定在主線程中執行

2.在主線程中,使用dispatch_async非同步執行非主隊列中任務,將產生新的子線程

 

使用示例二:

總結:

主線程卡死。該方法在block執行完之前不會return,而block也是在當前線程執行,所以互相等待,造成死鎖。

在主線程中使用同步執行主隊列任務,將死鎖。

 

使用示例三:

 

總結:

子線程卡死,UI依然可以操作。

綜合示例二和三,得出:在執行(同步或者非同步)串列隊列的線程中再使用dispatch_sync同步執行當前串列隊列,將造成線程死鎖。

 

使用示例四:

總結:

調用dispatch_sync將在當前線程上依次執行添加的任務,不管是否在同一隊列中,也不管隊列類型。

 

使用示例五:

    LOG(@"測試GCD dispatch_async混合dispatch_sync");
    LOG(@"mainThread : %@", [NSThread mainThread]);

    dispatch_async(customSerialQueue, ^{
        LOG(@"level 1 dispatch_async No.1 customSerialQueue : %@", [NSThread currentThread]);
        
        dispatch_async(customSerialQueue, ^{
            LOG(@"level 2 dispatch_async No.1 customSerialQueue : %@", [NSThread currentThread]);
        });
        
        dispatch_async(customSerialQueue, ^{
            LOG(@"level 2 dispatch_async No.2 customSerialQueue : %@", [NSThread currentThread]);
        });
        
        dispatch_async(customSerialQueue, ^{
            LOG(@"level 2 dispatch_async No.3 customSerialQueue : %@", [NSThread currentThread]);
        });
        
        //==============================
        dispatch_async(customConcurrentQueue, ^{
            LOG(@"level 2 dispatch_async No.4 customConcurrentQueue : %@", [NSThread currentThread]);
        });
        
        dispatch_async(customConcurrentQueue, ^{
            LOG(@"level 2 dispatch_async No.5 customConcurrentQueue : %@", [NSThread currentThread]);
        });
        
        dispatch_async(customConcurrentQueue, ^{
            LOG(@"level 2 dispatch_async No.6 customConcurrentQueue : %@", [NSThread currentThread]);
        });
        
        //==============================
        dispatch_sync(customConcurrentQueue, ^{
            LOG(@"level 2 dispatch_sync No.7 customConcurrentQueue : %@", [NSThread currentThread]);
        });
        
        dispatch_sync(customConcurrentQueue, ^{
            LOG(@"level 2 dispatch_sync No.8 customConcurrentQueue : %@", [NSThread currentThread]);
        });
        
        dispatch_sync(customConcurrentQueue, ^{
            LOG(@"level 2 dispatch_sync No.9 customConcurrentQueue : %@", [NSThread currentThread]);
        });
    });

    dispatch_async(customConcurrentQueue, ^{
        LOG(@"level 1 dispatch_async No.2 customConcurrentQueue : %@", [NSThread currentThread]);
        
        dispatch_sync(customSerialQueue, ^{
            LOG(@"level 2 dispatch_sync No.10 customSerialQueue : %@", [NSThread currentThread]);
        });
        
        dispatch_sync(customSerialQueue, ^{
            LOG(@"level 2 dispatch_sync No.11 customSerialQueue : %@", [NSThread currentThread]);
        });
        
        dispatch_sync(customSerialQueue, ^{
            LOG(@"level 2 dispatch_sync No.12 customSerialQueue : %@", [NSThread currentThread]);
        });
        
        //==============================
        dispatch_async(customConcurrentQueue, ^{
            LOG(@"level 2 dispatch_async No.13 customConcurrentQueue : %@", [NSThread currentThread]);
        });
        
        dispatch_async(customConcurrentQueue, ^{
            LOG(@"level 2 dispatch_async No.14 customConcurrentQueue : %@", [NSThread currentThread]);
        });
        
        dispatch_async(customConcurrentQueue, ^{
            LOG(@"level 2 dispatch_async No.15 customConcurrentQueue : %@", [NSThread currentThread]);
        });
        
        //==============================
        dispatch_async(customSerialQueue, ^{
            LOG(@"level 2 dispatch_async No.16 customSerialQueue : %@", [NSThread currentThread]);
        });
        
        dispatch_async(customSerialQueue, ^{
            LOG(@"level 2 dispatch_async No.17 customSerialQueue : %@", [NSThread currentThread]);
        });
        
        dispatch_async(customSerialQueue, ^{
            LOG(@"level 2 dispatch_async No.18 customSerialQueue : %@", [NSThread currentThread]);
        });
    });

總結:

1.串列隊列customSerialQueue,只關註任務加入的先後順序,不管是同步還是非同步執行,總體順序不變

2.多個同步執行的同一串列隊列,如果加入了另一個執行隊列,他們的執行線程相同

3.多個非同步執行的同一串列隊列,如果加入了另一個執行隊列,他們的執行線程相同

4.綜合上述,使用dispatch_sync,一定是在當前線程執行;使用dispatch_async,不一定產生新的子線程,如果在同一級下,執行串列隊列,將使用已存在的同一線程。

5.多個嵌套的非同步執行並行隊列,可能使用已存在的閑置線程

 

void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);

該方法與dispatch_async類似,將block加入隊列非同步執行。註意當輪到該block執行時候,唯一非同步執行,執行完畢後才會執行其他任務。所以只有加入並行隊列,該方法才有意義。特別適用於加鎖操作。

 

void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);

將block將入隊列,延遲一定時間後非同步執行。

使用示例:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        //code to be executed after a specified delay

});

表示在5秒以後,將block加入主隊列非同步執行。

 

void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t));

將block加入隊列指定次數。隊列可以是並行的,所以block執行可以為並行。size_t表示加入時的索引。

測試代碼:

  dispatch_apply(10, globalQueue, ^(size_t index) {

        LOG(@"dispatch_apply : %zu", index);

  });

2016-09-30 16:57:33.023 base[33146:8699303] dispatch_apply : 0
2016-09-30 16:57:33.023 base[33146:8699545] dispatch_apply : 1
2016-09-30 16:57:33.023 base[33146:8699530] dispatch_apply : 2
2016-09-30 16:57:33.024 base[33146:8699631] dispatch_apply : 3
2016-09-30 16:57:33.024 base[33146:8699303] dispatch_apply : 4
2016-09-30 16:57:33.024 base[33146:8699303] dispatch_apply : 8
2016-09-30 16:57:33.024 base[33146:8699303] dispatch_apply : 9
2016-09-30 16:57:33.024 base[33146:8699545] dispatch_apply : 5
2016-09-30 16:57:33.024 base[33146:8699530] dispatch_apply : 6
2016-09-30 16:57:33.024 base[33146:8699631] dispatch_apply : 7

 

void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);

只執行block中代碼一次。特別適用於單例模式。

使用示例:

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

    });

 

void dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);

該方法將加入隊列的block分組管理,特別適用於多方法並行,最後整合全部結果。第一個參數由如下方法得到:

dispatch_group_t dispatch_group_create(void);

 

void dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);

該方法用於group中所有任務都完成後,回調block內容。

示例代碼:

    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, globalQueue, ^{
        LOG(@"dispatch_group_async : 1");
    });
    
    dispatch_group_async(group, globalQueue, ^{
        LOG(@"dispatch_group_async : 2");
    });
    
    dispatch_group_async(group, globalQueue, ^{
        LOG(@"dispatch_group_async : 3");
    });
    
    dispatch_group_async(group, globalQueue, ^{
        LOG(@"dispatch_group_async : 4");
    });
    
    dispatch_group_notify(group, globalQueue, ^{
        LOG(@"dispatch_group_async : completion");
    });

2016-09-30 17:19:15.490 base[33322:8718096] dispatch_group_async : 1
2016-09-30 17:19:15.490 base[33322:8718097] dispatch_group_async : 3
2016-09-30 17:19:15.490 base[33322:8718042] dispatch_group_async : 2
2016-09-30 17:19:15.490 base[33322:8718098] dispatch_group_async : 4
2016-09-30 17:19:15.491 base[33322:8718098] dispatch_group_async : completion

 

以上記錄了GCD的常見使用方法和示例代碼。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 對項目的說明: 前一段時間移動端網站中要求實現一個“內容觸摸滑動”的功能,需求如下: 1. 通過點擊小圖顯示大圖; 2. 再次點擊大圖回到原來的小圖; 3. 圖片能夠滑動切換; 4. 顯示當前圖片的索引(目前我正在瀏覽哪一張圖片)。 自己寫了一些功能,完成了第 1、2 的需求,但是由於 js 基礎較 ...
  • 上圖: 聲明 字元串連接 截取字元串 轉換大小寫 字元串比較 檢索字元串 查找替換字元串 特殊字元 \b : 後退符 \t : 水平製表符 \n : 換行符 \v : 垂直製表符 \f : 分頁符 \r : 回車符 \” : 雙引號 \’ : 單引號 \ 反斜桿 特殊字元 \b : 後退符 \t : ...
  • 本系列主要記錄javascript中,新手比較容易搞錯的地方。 (1)要特別註意相等運算符==。JavaScript在設計時,有兩種比較運算符:第一種是==比較,它會自動轉換數據類型再比較,很多時候,會得到非常詭異的結果;第二種是 比較,它不會自動轉換數據類型,如果數據類型不一致,返回false,如 ...
  • 上圖 ·聲明 ·獲取時間的某部分 ·計算之前和未來的時間 ·計算兩個日期的偏移量 ·檢查有效日期 ...
  • CSS3就是出了不少高大上的功能,3D效果、動畫、多列等等。今天寫篇文章記錄怎麼一下怎麼用CSS3寫一個動畫。 醜話還得說前頭,IE9以及以下版本不支持CSS3動畫(如真要實現可以考慮用js,不過估計效果也不太好)。chrome和safafi建議加上首碼-webkit-以向前相容老版本。 今天簡單的 ...
  • 上代碼: counter-reset 屬性設置某個選擇器出現次數的計數器的值。預設為 0。 counter-increment 屬性設置某個選取器每次出現的計數器增量。預設增量是 1。 counter()插入計數器 ...
  • ...
  • Ext.window.MessageBox是一個工具類,他繼承自Ext.window.Windoe對象,用來生成各種風格的信息提示對話框,其實例對象可以通過Ext.MessageBox或Ext.Msg進行訪問,使用Ext.MessageBox和使用Ext.Msg有相同的效果,而後者提供了更簡短的調用 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...