首先,我們先來看一下GCD 的簡單介紹.
GCD是 Apple 開發(fā)的一個多核編程的解決方法,簡單易用,效率高,速度快。通過 GCD,開發(fā)者只需要向隊列中添加一段代碼塊(block或C函數(shù)指針),而不需要直接和線程打交道。GCD在后端管理著一個線程池,它不僅決定著你的代碼塊將在哪個線程被執(zhí)行,還根據(jù)可用的系統(tǒng)資源對這些線程進行管理。這樣通過GCD來管理線程,從而解決線程被創(chuàng)建的問題。
學(xué)習(xí)GCD 之前,先來了解 GCD 中兩個核心概念:任務(wù)和隊列。
任務(wù):就是執(zhí)行操作的意思,換句話說就是你在線程中執(zhí)行的那段代碼。在 GCD 中是放在 block 中的。
執(zhí)行任務(wù)有兩種方式:同步執(zhí)行(sync)和異步執(zhí)行(async)。兩者的主要區(qū)別是:是否等待隊列的任務(wù)執(zhí)行結(jié)束,以及是否具備開啟新線程的能力。
同步執(zhí)行(sync):
同步添加任務(wù)到指定的隊列中,在添加的任務(wù)執(zhí)行結(jié)束之前,會一直等待,直到隊列里面的任務(wù)完成之后再繼續(xù)執(zhí)行。
只能在當(dāng)前線程中執(zhí)行任務(wù),不具備開啟新線程的能力。
異步執(zhí)行(async):
異步添加任務(wù)到指定的隊列中,它不會做任何等待,可以繼續(xù)執(zhí)行任務(wù)。
可以在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力。
隊列(Dispatch Queue):這里的隊列指執(zhí)行任務(wù)的等待隊列,即用來存放任務(wù)的隊列。隊列是一種特殊的線性表,采用 FIFO(先進先出)的原則,即新任務(wù)總是被插入到隊列的末尾,而讀取任務(wù)的時候總是從隊列的頭部開始讀取。每讀取一個任務(wù),則從隊列中釋放一個任務(wù)。
在 GCD 中有兩種隊列:串行隊列和并發(fā)隊列。兩者都符合 FIFO(先進先出)的原則。兩者的主要區(qū)別是:執(zhí)行順序不同,以及開啟線程數(shù)不同。
串行隊列(Serial Dispatch Queue):
每次只有一個任務(wù)被執(zhí)行。讓任務(wù)一個接著一個地執(zhí)行。(只開啟一個線程,一個任務(wù)執(zhí)行完畢后,再執(zhí)行下一個任務(wù))
并發(fā)隊列(Concurrent Dispatch Queue):
可以讓多個任務(wù)并發(fā)(同時)執(zhí)行。(可以開啟多個線程,并且同時執(zhí)行任務(wù))
下面有代碼具體演示執(zhí)行方式與隊列結(jié)合使用的時候,各種情況的區(qū)別.
1.串行隊列 同步執(zhí)行
NSLog(@"開始了");
dispatch_queue_t serQueue = dispatch_queue_create("feng", DISPATCH_QUEUE_SERIAL);
dispatch_sync(serQueue, ^{
for (int i = 0; i<10; i++) {
NSLog(@"1111-%d --- %@", i, [NSThread currentThread]);
}
});
dispatch_sync(serQueue, ^{
for (int i = 0; i<10; i++) {
NSLog(@"2222-%d --- %@", i, [NSThread currentThread]);
}
});
NSLog(@"結(jié)束了");

如上圖所示,任務(wù)一加入就開始執(zhí)行, 并且按照順序執(zhí)行, 不開辟線程.
2.串行隊列 異步執(zhí)行
NSLog(@"開始了");
dispatch_queue_t serQueue = dispatch_queue_create("feng", DISPATCH_QUEUE_SERIAL);
dispatch_async(serQueue, ^{
for (int i = 0; i<10; i++) {
NSLog(@"1111-%d --- %@", i, [NSThread currentThread]);
}
});
dispatch_async(serQueue, ^{
for (int i = 0; i<10; i++) {
NSLog(@"2222-%d --- %@", i, [NSThread currentThread]);
}
});
NSLog(@"結(jié)束了");

如上圖所示,任務(wù)全部加入才開始執(zhí)行, 按照順序執(zhí)行, 開辟線程.
3.并行隊列 同步執(zhí)行
NSLog(@"開始了");
dispatch_queue_t serQueue = dispatch_queue_create("feng", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(serQueue, ^{
for (int i = 0; i<10; i++) {
NSLog(@"1111-%d --- %@", i, [NSThread currentThread]);
}
});
dispatch_sync(serQueue, ^{
for (int i = 0; i<10; i++) {
NSLog(@"2222-%d --- %@", i, [NSThread currentThread]);
}
});
NSLog(@"結(jié)束了");

如上圖所示,任務(wù)一加入就開始執(zhí)行, 按照順序執(zhí)行, 不開辟線程.
4.并行隊列 異步執(zhí)行
NSLog(@"開始了");
dispatch_queue_t serQueue = dispatch_queue_create("feng", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(serQueue, ^{
for (int i = 0; i<10; i++) {
NSLog(@"1111-%d --- %@", i, [NSThread currentThread]);
}
for (int i = 0; i<10; i++) {
NSLog(@"2222-%d --- %@", i, [NSThread currentThread]);
}
});
dispatch_async(serQueue, ^{
for (int i = 0; i<10; i++) {
NSLog(@"3333-%d --- %@", i, [NSThread currentThread]);
}
for (int i = 0; i<10; i++) {
NSLog(@"4444-%d --- %@", i, [NSThread currentThread]);
}
});
NSLog(@"結(jié)束了");

如上圖所示,任務(wù)全部加入才開始執(zhí)行, 并發(fā)執(zhí)行, 開辟線程.
總結(jié):
1.同步(dispatch_sync) 任務(wù)一進入任務(wù)就直接開始執(zhí)行. 不開辟線程.
2.異步(dispatch_async) 所有的任務(wù)都進入了,才開始執(zhí)行,會開辟線程.
追加的其他功能:
柵欄函數(shù)dispatch_barrier_async的使用
// 1.創(chuàng)建并發(fā)隊列
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
// 2.向隊列中添加任務(wù)
dispatch_async(queue, ^{ // 1.2是并行的
NSLog(@"任務(wù)1, %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任務(wù)2, %@",[NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
NSLog(@"任務(wù) barrier, %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{ // 這兩個是同時執(zhí)行的
NSLog(@"任務(wù)3, %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"任務(wù)4, %@",[NSThread currentThread]);
});

如上圖所示,注意: 輸出結(jié)果: 任務(wù)1 任務(wù)2 ——》 任務(wù) barrier ——》任務(wù)3 任務(wù)4
// 其中的任務(wù)1與任務(wù)2,任務(wù)3與任務(wù)4 由于是并行處理先后順序不定。