1. 程式人生 > >完整詳解 swift GCD系列(一)dispatch_async;dispatch_sync;dispatch_async_f;dispatch_sync_f

完整詳解 swift GCD系列(一)dispatch_async;dispatch_sync;dispatch_async_f;dispatch_sync_f

為什麼要寫這個系列,因為百度了一下,找了很多都是些片面的Blog,拷貝來拷貝去的,寫的也很粗糙。

所以,我要寫這個系列,儘量把官網文件中GCD的強大功能完整的表達出來。方便自己,也方便別人,如果發現有問題,歡迎提出

本教程的計劃:在完整的看過GCD的官方文件之後,我實在想不出來如何用一篇文章詳細完整的寫出來如此多的功能。
所以,決定開一個專欄來寫這個教程。計劃8篇文章,分別介紹各種功能,每種功能會附上簡單完整的示例程式碼。最後

的一篇文章會進行總結,總結出GCD的經典使用場景。原始碼只提供Swift版本。因為要上班,計劃一個月內完成。每週兩篇。

原創Blog,轉載請註明出處

這個專欄地址


GCD

全稱:Grand Central Dispatch 
簡介:GCD是對多執行緒、多核開發較完整的封裝。在使用GCD的時候,系統會自動根據CPU使用情況進行排程,所以GCD是
一個簡單易用,但是效果很好地多執行緒多核開發工具

要注意的地方:
1、慎用fork()函式(不是十分清楚流程不要用)
2、GCD是C語言級別的API,所以不會抓到異常,在一個提交到GCD的任務完成之前,應當處理完異常。


教程一

教程一涵蓋了
1、GCD全域性佇列的四個優先順序
2、幾種本文使用到的GCD型別
3、dispatch_async/dispatch_async_f
4、dispatch_sync/dispatch_sync_f


一、概念與型別

對於GCD來說,所有的執行都放到佇列中(queue),佇列的特點是FIFO(先提交的先執行)。
GCD的佇列分為幾種,主佇列(main),全域性佇列(global),使用者建立佇列(create)
對於全域性佇列,預設有四個,分為四個優先順序
  1. #define DISPATCH_QUEUE_PRIORITY_HIGH         2
  2. #define DISPATCH_QUEUE_PRIORITY_DEFAULT      0
  3. #define DISPATCH_QUEUE_PRIORITY_LOW          (-2)
  4. #define DISPATCH_QUEUE_PRIORITY_BACKGROUND   INT16_MIN


DISPATCH_QUEUE_PRIORITY_HIGH:優先順序最高,在default,和low之前執行
DISPATCH_QUEUE_PRIORITY_DEFAULT 預設優先順序,在low之前,在high之後
DISPATCH_QUEUE_PRIORITY_LOW 在high和default後執行
DISPATCH_QUEUE_PRIORITY_BACKGROUND:提交到這個佇列的任務會在high優先順序的任務和已經提交到background佇列的執行完後執行。官方文件:(the queue is scheduled for execution after all high priority queues have been scheduled and the system runs items on a thread whose priority is set for background status.)


幾種使用到的型別
  1. typealias dispatch_queue_t = NSObject //輕量級的用來描述執行任務的佇列
  2. typealias dispatch_block_t = () -> Void //佇列執行的閉包(Objective C中的block)

幾個概念
非同步提交的任務立刻返回,在後臺佇列中執行
同步提交的任務在執行完成後才會返回
並行執行(全域性佇列)提交到一個佇列的任務,比如提交了任務1和任務2,在任務1開始執行,並且沒有執行完畢時候,任務2就可以開始執行。
序列執行(使用者建立佇列) 提交到一個佇列中的任務,比如提交了任務1和任務2,只有任務1結束後,任務2才可執行

注意:提交到佇列中的任務是序列執行,還是並行執行由佇列本身決定。

二、示例詳解
  1. func dispatch_async(_ queue: dispatch_queue_t!,  
  2.                   _ block: dispatch_block_t!)  
引數:
queue 提交到的佇列,佇列的型別決定了是序列還是並行執行佇列中的任務
block 執行的閉包
  1. func dispatch_async_f(_ queue: dispatch_queue_t!,  
  2.                     _ context: UnsafeMutablePointer<Void>,  
  3.                     _ work: dispatch_function_t)  
引數
queue 提交到的佇列,佇列的型別決定了是序列還是並行執行佇列中的任務
context 傳遞給work的引數

work 執行的函式(C語言函式)

dispatch_sync 和 dispatch_sync的引數和上述對應一致,所以不再列出

總得來說帶有後綴_f(比如dispatch_sync_f,dispatch_after_f)就是提交給佇列一個C語言函式,因為極少用到這種形式,這裡僅給出一個簡單例子,後面的涉及到_f的都略過。

1、dispatch_async/dispatch_sync
功能:提交到佇列中非同步/同步執行
本示例:下載一張圖片,圖片下載完畢後通知UI改變
注意:要改變UI必須在主佇列上執行
這裡用到了一個獲取全域性佇列的函式
  1. func dispatch_get_global_queue(_ identifier: Int,  
  2.                              _ flags: UInt) -> dispatch_queue_t!  
這個函式的第一個引數是佇列的優先順序,第二個引數尚沒有意義,直接寫0就可以了。

建立一個基於單頁面的Swift工程,然後在ViewController.swift中,
  1. class ViewController: UIViewController{    
  2.     var imageview = UIImageView(frame: CGRectMake(40,40,200,200))    
  3.     override func viewDidLoad(){    
  4.         super.viewDidLoad()    
  5.         imageview.contentMode = UIViewContentMode.ScaleAspectFit    
  6.         self.view.addSubview(imageview)    
  7.         let url = "http://f.hiphotos.baidu.com/image/pic/item/e1fe9925bc315c60191d32308fb1cb1348547760.jpg"    
  8.         let imageURL = NSURL(string:url)     
  9.     var globalQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)  
  10.     dispatch_async(globalQueueDefault){  
  11.         var imageData = NSData(contentsOfURL:imageURL!)  
  12.         var image = UIImage(data:imageData!)  
  13.         if let successfulImage = image{  
  14.             sleep(2)  
  15.             dispatch_async(dispatch_get_main_queue()){  
  16.                 self.imageview.image = successfulImage  
  17.             }  
  18.         }  
  19.     }  
  20.     }    
  21.     override func didReceiveMemoryWarning(){    
  22.         super.didReceiveMemoryWarning()    
  23.     }    
  24. }    
執行,觀察下效果:view立刻載入,然後過一段時間,圖片下載完了,UI改變
然後,我們觀察dispatch_sync
只需要修改這一行即可

  1. dispatch_sync(globalQueueDefault,0){  

執行,觀察下效果:view載入很慢,但是在載入的時候,圖片下載完了。UI已經改變。可以打在這一行打斷點,會發現非同步執行會立刻返回,同步執行會等待執行結束後返回。
所以,當我們有一件非常耗時的事情,放到後臺佇列中去做,等做完了通知UI改變,是不會阻塞UI,降低使用者體驗的。


2、dispatch_async_f/dispatch_sync_f

簡單的例項,把一個C函式提交給佇列
首先,建立一個基於單頁面的swift工程,命名為testForCSDN,然後再新建一個C語言檔案,命名為hwcText->點選包括標頭檔案->點選包含Bridging-Header.h
這樣,工程裡多了三個檔案
hwcTest.c
hwcTest.h
testForCSDN-Bridging-Header.h
附上完整的程式碼
testForCSDN-Bridging-Header.h
  1. #import "hwcTest.h"

hwcTest.h
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. typedefvoid (*hwcTestForGCD)(void*);  
  4. hwcTestForGCD getFuncPointer();  

hwcTest.c
  1. #include "hwcTest.h"
  2. void realFunction(void *input){  
  3.     for(int i = 0;i < 5;i++){  
  4.         printf("%d\n",i);  
  5.         sleep(1);  
  6.     }  
  7. }  
  8. hwcTestForGCD getFuncPointer(){  
  9.     return realFunction;  
  10. }  
ViewController.swift
  1. class ViewController: UIViewController{    
  2.     var imageview = UIImageView(frame: CGRectMake(40,40,200,200))    
  3.     override func viewDidLoad(){    
  4.         super.viewDidLoad()    
  5.         var globalQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)  
  6.     dispatch_async_f(globalQueueDefault,nil,getFuncPointer())  
  7.     println("dispatch is over")  
  8.     }    
  9.     override func didReceiveMemoryWarning(){    
  10.         super.didReceiveMemoryWarning()    
  11.     }    
  12. }   
然後執行,會發現輸出
  1. 0  
  2. dispatch is over  
  3. 1  
  4. 2  
  5. 3  
  6. 4  

然後,我們同樣改成dispatch_sync後執行,發現輸出
  1. 0  
  2. 1  
  3. 2  
  4. 3  
  5. 4  
  6. 5  
  7. dispatch is over  
這裡更能體會到了,什麼是同步,什麼是非同步了吧。


三、理解下並行佇列和序列佇列
使用一或者二中的工程都可以,修改ViewController.swft中的程式碼就可以
這裡用到了一個函式
  1. func dispatch_queue_create(_ label: UnsafePointer<Int8>,  
  2.                          _ attr: dispatch_queue_attr_t!) -> dispatch_queue_t!  
引數
label String型別的佇列標示符,通常取做com.companyname.productname.functionname
attr   兩種型別。DISPATCH_QUEUE_SERIAL建立一個順序執行佇列, DISPATCH_QUEUE_CONCURRENT建立同時執行佇列


ViewController的完整程式碼,這裡提交兩個任務,通過輸出來判斷是並行佇列,還是序列佇列

  1. class ViewController: UIViewController{    
  2.     var imageview = UIImageView(frame: CGRectMake(40,40,200,200))    
  3.     override func viewDidLoad(){    
  4.         super.viewDidLoad()   
  5.     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)){  
  6.         for var i = 0;i < 5;i++ {  
  7.             NSLog("First task:%d",i)  
  8.             sleep(1)  
  9.         }  
  10.     }  
  11.     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)){  
  12.         for var j = 0;j < 5;j++ {  
  13.             NSLog("Second task:%d",j)  
  14.             sleep(1)  
  15.         }  
  16.     }  
  17.     println("dispatch is over")  
  18.     }    
  19.     override func didReceiveMemoryWarning(){    
  20.         super.didReceiveMemoryWarning()    
  21.     }    
  22. }   

這裡執行輸出為:

  1. First task:0  
  2. Second task:0  
  3. First task:1  
  4. Second task:1  
  5. First task:2  
  6. Second task:2  
  7. First task:3  
  8. Second task:3  
  9. First task:4  
  10. Second task:4  
這段程式碼執行時間4.03s 然後,我們使用序列執行的佇列

相關推薦

完整 swift GCD系列dispatch_async;dispatch_sync;dispatch_async_f;dispatch_sync_f

為什麼要寫這個系列,因為百度了一下,找了很多都是些片面的Blog,拷貝來拷貝去的,寫的也很粗糙。 所以,我要寫這個系列,儘量把官網文件中GCD的強大功能完整的表達出來。方便自己,也方便別人,如果發現有問題,歡迎提出 本教程的計劃:在完整的看過GCD的官方文件之後,我實在想

完整swift GCD系列dispatch_group

原創Blog,轉載請註明出處http://blog.csdn.net/column/details/swift-gcd.html一、dispatch_group把一組任務提交到佇列中,這些佇列可以不相關,然後堅挺這組任務完成的事件。幾個用到的函式1、dispatch_gro

C#泛型

安全 情況 重用 模板 信息 普通 cast 綁定 封閉式   一、C#中的泛型引入了類型參數的概念,類似於C++中的模板,類型參數可以使類型或方法中的一個或多個類型的指定推遲到實例化或調用時,使用泛型可以更大程度的重用代碼、保護類型安全性並提高性能;可以創建自定義的泛型類

例項js閉包閉包基本概念及其作用推導

  在學習前端的過程中,不可避免的要學習到js閉包這個知識點,很多朋友感到對閉包很難理解,也不清楚它有什麼用。本文就詳細介紹一下閉包,並通過幾個小例子來說明下閉包的用處。  一、閉包的概念       閉包的英文單詞是Closure,我先給閉包可

Spring Boot Actuator與深入應用:Actuator 1.x

《Spring Boot Actuator詳解與深入應用》預計包括三篇,第一篇重點講Spring Boot Actuator 1.x的應用與定製端點;第二篇將會對比Spring Boot Actuator 2.x 與1.x的區別,以及應用和定製2.x的端點;第三篇將會介紹Actuator metric指

C#泛型 C#泛型 C#泛型

  一、前面兩篇文章分別介紹了定義泛型型別、泛型委託、泛型介面以及宣告泛型方法:   詳解C#泛型(一)   詳解C#泛型(二)   首先回顧下如何構建泛型類: public class MyClass<T> { public void MyFunc() {

【MapReduce及原始碼解析】——分片輸入、Mapper及Map端Shuffle過程

title: 【MapReduce詳解及原始碼解析(一)】——分片輸入、Mapper及Map端Shuffle過程 date: 2018-12-03 21:12:42 tags: Hadoop categories: 大資料 toc: true 點選檢視我的部落格:Josonlee’

TensorFlow貓狗識別--讀取自己的資料集

資料集下載 連結: https://pan.baidu.com/s/1SlNAPf3NbgPyf93XluM7Fg 密碼: hpn4 資料集分別有12500張cat,12500張dog 讀取資料集 資料集的讀取,查閱了那麼多文件,大致瞭解到,資料集的讀取方法大概會分為兩種

javascript拖拽基礎介紹

人類喜歡將工作或活動步驟化:第一步、第二步、第三步等,因為分解讓人類得以分工並優化區域性。 一個作家構思一部鴻篇鉅製,必然要考慮將內容劃分為幾個部分,每個部分刻畫相應的人物背景故事. 同理,我們也將今天的主角拖拽分為 拖、放兩個步驟,來討論分析. 拖拽的歷史 拖拽成為一項標準也是近幾年的事,屬於

ALV:Function ALV

Function ALV Layout結構 Fieldcat結構 ALV相關函式 簡單例項 Fieldcat動態建立 通過程式設計建立 通過REUSE_ALV_FIELDCATALOG_MERGE函式建立 自定義ALV工具條 快速拷貝GUI Status

計算機網路--P2P對等網路—BitTorrent協議

注:本篇文章內容借鑑自:淺入淺出BitTorrent協議,其中加入了博主的部分原創,感謝,侵刪~ 對等網路的概念 以下定義主要摘抄自維基百科與中科院計算技術研究所: 對等式網路(peer-to-peer,簡稱P2P),又稱點對點技術,是無中心伺服器、

JS作用域

一、什麼是作用域 儲存和訪問變數,是任何一種程式語言最基本的功能之一,變數存在哪裡?程式需要時如何找到它?這些問題需要一套良好的規則來規範,這套規則,就成為作用域。 二、編譯原理 js通常歸類為解釋語言,但它其實是編譯語言,和傳統編譯語言不同,它不是提前編譯,編譯結果也不能在分散式系統中進行移植。js引

完整GCD系列dispatch_group

/////-------------注意----------------這篇文章是在Swift 1.0時代寫的,已經不適合當前的語法。關於Swift最新版本的GCD,參見我的這篇部落格GCD精講/////-------------注意----------------一、dis

完整GCD系列dispatch_after;dispatch_apply;dispatch_

本教涵蓋的內容 一、dispatch_after 二、dispatch_apply  三、dispatch_once一、dispatch_after 功能:延遲一段時間把一項任務提交到佇列中執行,返回之後就不能取消 常用來在在主佇列上延遲執行一項任務 函式原型func dispatch_after(_ wh

yuv系列---YUV444

存儲空間 根據 字節 roc 排列 原因 每一個 mar size 本篇詳細分析YUV444格式: 一、文字描述首先從文字敘述的角度來講,這個格式相對比較簡單一些,就是真對每一個像素都要分別采樣Y, U, V的值。從物理存儲的角度來講,也就是每一個像素的表示都需要有3個字節

常見圖片格式系列 ----簡介

圖片格式 png jpg bmp 常見圖片格式介紹 信息時代,豐富多彩的世界,我們用圖片來感知,來記憶,來存儲。多姿多彩的圖片格式,你是否了解其中奧妙呢。接下來的系列文章就要帶大家詳細解析常見圖片格式。 (一) BMP BMP格式,是windows的一種位圖格式,同時也是一種未經過壓縮的格式

深入淺出javaEE系列---web.xml配置

web.xml是web專案最重要的一個檔案 一:定義頭和根元素 <?xml version="1.0" encoding="UTF-8"?>         部署描述符檔案就像所有xml檔案一樣,必須以一個xml頭開始。這個頭宣告必

sip協議 系列

近期一直在研究視訊通話,裡面有sip或者xmpp,之前也不瞭解, 準備整體瞭解sip並整理相關內容。 Sip概述 SIP(Session Initiation Protocol,會話初始協議)是由IETF(Internet Engineering Task Force,因特網工程任務組)

SVM系列:感知機

什麼是感知機 感知機是二類分類的線性分類模型,其輸入為例項的特徵向量,輸出為例項的類別,取+1和-1二值。 感知機對應於輸入空間(特徵空間)中將例項分為正負兩類的分離超平面,屬於判別模型。 感知機旨在求出將訓練資料進行線性劃分的分離超平面,為此,匯入基於誤分類的損失函式,利用梯度

中文分詞系列 雙陣列Tire樹(DART)

雙陣列Tire樹是Tire樹的升級版,Tire取自英文Retrieval中的一部分,即檢索樹,又稱作字典樹或者鍵樹。下面簡單介紹一下Tire樹。 1.1 Tire樹 Trie是一種高效的索引方法,它實際上是一種確定有限自動機(DFA),在樹的結構中,每一個結點對應一個DFA狀態,每一個從父結點指向子結點