GCD核心概念:任務和隊列
任務:在線程中執行的那段代碼。執行方式有兩種:同步執行和異步執行
* 同步執行:只能在當前線程執行,不具有開啟新線程的能力(dispatch_sync)
* 異步執行:可以在新線程中執行任務,具有開啟新線程的能力(dispatch_async)
隊列:這里的隊列指任務隊列,即用來存放任務的隊列。隊列是一種特殊的線性表,采用FIFO(先進先出)的原則,即新任務總是被插入到隊列的末尾,而讀取任務的時候總是從隊列的頭部開始讀取。每讀取一個任務,則從隊列中釋放一個任務。在GCD中有兩種隊列:串行隊列和并發隊列。
* 并發隊列(Concurrent Dispatch Queue):可以讓多個任務并發(同時)執行(自動開啟多個線程同時執行任務)
? ? ? ? ? 1)并發功能只有在異步(dispatch_async)函數下才有效
* 串行隊列(Serial Dispatch Queue):讓任務一個接著一個地執行(一個任務執行完畢后,再執行下一個任務)
GCD的使用步驟
1、創建一個隊列(串行隊列或并發隊列)
2、將任務添加到隊列中,然后系統就會根據任務類型執行任務(同步執行或異步執行)
1. 隊列的創建方法
可以使用dispatch_queue_create來創建對象,需要傳入兩個參數,第一個參數表示隊列的唯一標識符,用于DEBUG,可為空;第二個參數用來識別是串行隊列還是并發隊列。DISPATCH_QUEUE_SERIAL表示串行隊列,DISPATCH_QUEUE_CONCURRENT表示并發隊列。
// 串行隊列的創建方法
dispatch_queue_tqueue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
// 并發隊列的創建方法
dispatch_queue_tqueue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);
對于并發隊列,還可以使用dispatch_get_global_queue來創建全局并發隊列。GCD默認提供了全局的并發隊列,需要傳入兩個參數。第一個參數表示隊列優先級,一般用DISPATCH_QUEUE_PRIORITY_DEFAULT。第二個參數暫時沒用,用0即可。
2. 任務的創建方法
// 同步執行任務創建方法
dispatch_sync(queue, ^{
? ? ? ? ? NSLog(@"%@",[NSThreadcurrentThread]);
? ? ? ? ? // 這里放任務代碼
});
// 異步執行任務創建方法
dispatch_async(queue, ^{
? ? ? ? ? ?NSLog(@"%@",[NSThreadcurrentThread]);
? ? ? ? ? ? // 這里放任務代碼
});
GCD基本使用
1. 并發隊列 + 同步執行
- (void) syncConcurrent{
NSLog(@"syncConcurrent---begin");
dispatch_queue_tqueue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{for(inti =0; i <2; ++i) {
? ? ? ? NSLog(@"1------%@",[NSThreadcurrentThread]);?
}? ? });
dispatch_sync(queue, ^{for(inti =0; i <2; ++i) {
? ? ? ? NSLog(@"2------%@",[NSThreadcurrentThread]);? ? ? ?
}? ? });
dispatch_sync(queue, ^{for(inti =0; i <2; ++i) {
? ? ? ? NSLog(@"3------%@",[NSThreadcurrentThread]);? ? ? ?
}? ? });
NSLog(@"syncConcurrent---end");}
2. GCD的延時執行方法dispatch_after
當我們需要延遲執行一段代碼時,就需要用到GCD的dispatch_after方法。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0* NSEC_PER_SEC)), dispatch_get_main_queue(), ^{? ?
? ? ? // 2秒后異步執行這里的代碼...? NSLog(@"run-----");
});
3. GCD的一次性代碼(只執行一次)dispatch_once
我們在創建單例、或者有整個程序運行過程中只執行一次的代碼時,我們就用到了GCD的dispatch_once方法。使用dispatch_once函數能保證某段代碼在程序運行過程中只被執行1次。
staticdispatch_once_tonceToken;
dispatch_once(&onceToken, ^{
? ? ? ? ?// 只執行1次的代碼(這里面默認是線程安全的)
});
4. GCD的快速迭代方法dispatch_apply
通常我們會用for循環遍歷,但是GCD給我們提供了快速迭代的方法dispatch_apply,使我們可以同時遍歷。比如說遍歷0~5這6個數字,for循環的做法是每次取出一個元素,逐個遍歷。dispatch_apply可以同時遍歷多個數字。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_apply(6, queue, ^(size_tindex) {? ?
? ? ? ? ?NSLog(@"%zd------%@",index, [NSThread currentThread]);
});
5. GCD的隊列組dispatch_group
有時候我們會有這樣的需求:分別異步執行2個耗時操作,然后當2個耗時操作都執行完畢后再回到主線程執行操作。這時候我們可以用到GCD的隊列組。
我們可以先把任務放到隊列中,然后將隊列放入隊列組中。
調用隊列組的dispatch_group_notify回到主線程執行操作。
dispatch_group_t group =? dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{? ??
? ? ? // 執行1個耗時的異步操作});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{? ??
? ? ? // 執行1個耗時的異步操作
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
? ? ? // 等前面的異步操作都執行完畢后,回到主線程...
});