OS X 10.8或iOS 6以及以後版本中使用,Dispatch Queue將會由ARC自動管理,不須要手動釋放安全
分爲串行隊列和併發隊列併發
獲取隊列:app
建立隊列:異步
獲取隊列相關信息async
例子:ide
let globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) let group = dispatch_group_create() dispatch_group_async(group, globalQueue) { () -> Void in println("1") } dispatch_group_async(group, globalQueue) { () -> Void in println("2") } dispatch_group_async(group, globalQueue) { () -> Void in println("3") } dispatch_group_notify(group, globalQueue) { () -> Void in println("completed") }
輸出的順序與添加進隊列的順序無關,由於隊列是Concurrent Dispatch Queue,但「completed」的輸出必定是在最後的函數
let globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) let group = dispatch_group_create() dispatch_group_async(group, globalQueue) { () -> Void in println("1") } dispatch_group_async(group, globalQueue) { () -> Void in println("2") } dispatch_group_async(group, globalQueue) { () -> Void in println("3") } //使用dispatch_group_wait函數 dispatch_group_wait(group, DISPATCH_TIME_FOREVER) println("completed")
這些函數不會影響到隊列中已經執行的任務,隊列暫停後,已經添加到隊列中但尚未執行的任務不會執行,直到隊列被恢復spa
咱們知道數據在寫入時,不能在其餘線程讀取或寫入。可是多個線程同時讀取數據是沒有問題的。因此咱們能夠把讀取任務放入並行隊列,把寫入任務放入串行隊列,而且保證寫入任務執行過程當中沒有讀取任務能夠執行。線程
這樣的需求比較常見,GCD提供了一個很是簡單的解決辦法——dispatch_barrier_asynccode
假設咱們有四個讀取任務,在第二三個任務之間有一個寫入任務,代碼大概是這樣:
let queue = dispatch_queue_create("com.gcd.kt", DISPATCH_QUEUE_CONCURRENT) dispatch_async(queue, block1_for_reading) dispatch_async(queue, block2_for_reading) /* 這裏插入寫入任務,好比: dispatch_async(queue, block_for_writing) */ dispatch_async(queue, block3_for_reading) dispatch_async(queue, block4_for_reading)
若是代碼這樣寫,因爲這幾個block是併發執行,就有可能在前兩個block中讀取到已經修改了的數據。若是是有多寫入任務,那問題更嚴重,可能會有數據競爭。
若是使用dispatch_barrier_async函數,代碼就能夠這麼寫:
dispatch_async(queue, block1_for_reading) dispatch_async(queue, block2_for_reading) dispatch_barrier_async(queue, block_for_writing) dispatch_async(queue, block3_for_reading) dispatch_async(queue, block4_for_reading)
dispatch_barrier_async會把並行隊列的運行週期分爲這三個過程:
總的來講,dispatch_barrier_async起到了「承上啓下」的做用。它保證此前的任務都先於本身執行,此後的任務也遲於本身執行。正如barrier的含義同樣,它起到了一個柵欄、或是分水嶺的做用。
這樣一來,使用並行隊列和dispatc_barrier_async方法,就能夠高效的進行數據和文件讀寫了。
dispatch_semaphore
首先介紹一下信號量(semaphore)的概念。信號量是持有計數的信號,不過這麼解釋等於沒解釋。咱們舉個生活中的例子來看看。
假設有一個房子,它對應進程的概念,房子裏的人就對應着線程。一個進程能夠包括多個線程。這個房子(進程)有不少資源,好比花園、客廳等,是全部人(線程)共享的。
可是有些地方,好比臥室,最多隻有兩我的能進去睡覺。怎麼辦呢,在臥室門口掛上兩把鑰匙。進去的人(線程)拿着鑰匙進去,沒有鑰匙就不能進去,出來的時候把鑰匙放回門口。
這時候,門口的鑰匙數量就稱爲信號量(Semaphore)。很明顯,信號量爲0時須要等待,信號量不爲零時,減去1並且不等待。
在GCD中,建立信號量的語法以下:
var semaphore = dispatch_semaphore_create(2)
這句代碼經過dispatch_semaphore_create方法建立一個信號量並設置初始值爲2。而後就能夠調用dispatch_semaphore_wait方法了。
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
dispatch_semaphore_wait方法表示一直等待直到信號量的值大於等於一,當這個方法執行後,會把第一個信號量參數的值減1。
第二個參數是一個dispatch_time_t類型的時間,它表示這個方法最大的等待時間。這在第一章中已經講過,好比
DISPATCH_TIME_FOREVER表示永久等待。
返回值也和dispatch_group_wait方法同樣,返回0表示在規定的等待時間內第一個參數信號量的值已經大於等於1,不然表示已超過規定等待時間,但信號量的值仍是0。
dispatch_semaphore_wait方法返回0,由於此時的信號量的值大於等於一,任務得到了能夠執行的權限。這時候咱們就能夠安全的執行須要進行排他控制的任務了。
任務結束時還須要調用
dispatch_semaphore_signal()方法,將信號量的值加1。這相似於以前所說的,從臥室出來要把鎖放回門上,不然後來的人就沒法進入了。
咱們來看一個完整的例子:
var semaphore = dispatch_semaphore_create(1) let queue = dispatch_queue_create("com.gcd.kt", DISPATCH_QUEUE_CONCURRENT) var array: [Int] = [] for i in 1...100000 { dispatch_async(queue, { () -> Void in /* 某個線程執行到這裏,若是信號量值爲1,那麼wait方法返回1,開始執行接下來的操做。 與此同時,由於信號量變爲0,其它執行到這裏的線程都必須等待 */ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) /* 執行了wait方法後,信號量的值變成了0。能夠進行接下來的操做。 這時候其它線程都得等待wait方法返回。 能夠對array修改的線程在任意時刻都只有一個,能夠安全的修改array */ array.append(i) /* 排他操做執行結束,記得要調用signal方法,把信號量的值加1。 這樣,若是有別的線程在等待wait函數返回,就由最早等待的線程執行。 */ dispatch_semaphore_signal(semaphore) }) }
NSTimeInterval period = 1.0; //設置時間間隔 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), period * NSEC_PER_SEC, 0); //每秒執行 dispatch_source_set_event_handler(_timer, ^{ //在這裏執行事件 }); dispatch_resume(_timer);