GCD的基本思想
-
GCD的基本思想是將操作放在隊列中去執(zhí)行
(1)操作使用block定義。
(2)隊列負責(zé)調(diào)度任務(wù)執(zhí)行所在的線程以及具體的執(zhí)行時間。
(3)隊列的特點是先進先出,新添加到隊列的操作排在最后。 -
隊列 dispatch_queue_t
(1) DISPATCH_QUEUE_SERIAL:串行隊列,隊列中的任務(wù)只會順序執(zhí)行。
(2) DISPATCH_QUEUE_CONCURRENT:并行隊列,隊列中的任務(wù)通常會并發(fā)執(zhí)行。 -
操作
dispatch_async 異步操作,會并發(fā)執(zhí)行,不會順序執(zhí)行。
dispatch_sync 同步操作,會依次順序執(zhí)行,能決定任務(wù)執(zhí)行的順序。
一、DISPATCH_QUEUE_SERIAL: 串行隊列:
- (void) GCD
{
//DISPATCH_QUEUE_SERIAL串行隊列,會死鎖,但是會執(zhí)行嵌套同步操作之前的代碼
dispatch_queue_t queue = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"讀書===%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"吃飯====%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"上廁所====%@", [NSThread currentThread]);
});
}
2016-04-13 16:24:22.100 test[25089:1136445] 讀書===<NSThread: 0x7fb050700ee0>{number = 2, name = (null)}
2016-04-13 16:24:22.101 test[25089:1136445] 吃飯====<NSThread: 0x7fb050700ee0>{number = 2, name = (null)}
2016-04-13 16:24:22.102 test[25089:1136445] 上廁所====<NSThread: 0x7fb050700ee0>{number = 2, name = (null)}
可以看出來當(dāng)操作方式是dispatch_async時,只有兩個隊列,一個主線程,一個子線程,在子線程中執(zhí)行三個方法,所以異步操作是可以創(chuàng)建新線程的,而且操作會順序執(zhí)行的,這個非常有用,既不會影響主線程,又可以開啟新線程按順序執(zhí)行任務(wù)?,F(xiàn)在把操作方式改為dispatch_sync看一下打印結(jié)果:
2016-04-13 17:33:42.131 test[25342:1168870] 讀書===<NSThread: 0x7f8118d03bb0>{number = 1, name = main}
2016-04-13 17:33:42.131 test[25342:1168870] 吃飯====<NSThread: 0x7f8118d03bb0>{number = 1, name = main}
2016-04-13 17:33:42.132 test[25342:1168870] 上廁所====<NSThread: 0x7f8118d03bb0>{number = 1, name = main}
可以看出來只有一個線程,也就是主線程,所以證明了dispatch_sync是沒有開啟新線程的能力的。
二、DISPATCH_QUEUE_CONCURRENT:并行隊列
我們再把隊列的屬性改成DISPATCH_QUEUE_CONCURRENT試試,看下打印結(jié)果:
2016-04-13 17:44:38.296 test[25402:1175291] 上廁所====<NSThread: 0x7fdfe8f288a0>{number = 4, name = (null)}
2016-04-13 17:44:38.296 test[25402:1175301] 讀書===<NSThread: 0x7fdfe8f2bf10>{number = 2, name = (null)}
2016-04-13 17:44:38.296 test[25402:1175307] 吃飯====<NSThread: 0x7fdfe8e21cd0>{number = 3, name = (null)}
首先,可以看出,當(dāng)隊列的屬性是DISPATCH_QUEUE_CONCURRENT時,任務(wù)會無序執(zhí)行的,而且并行隊列DISPATCH_QUEUE_CONCURRENT是可以開啟新線程的。
得出結(jié)果當(dāng)隊列的屬性是DISPATCH_QUEUE_CONCURRENT并行隊列,操作是異步操作dispatch_async時,會創(chuàng)建多個線程,操作無序執(zhí)行。但是如果隊列錢有其他任務(wù),會等待其他任務(wù)執(zhí)行完成后再執(zhí)行其他的任務(wù)。適合的操作為:既不影響主線程,又不需要順序執(zhí)行的操作。
然后,我們再把操作改為dispatch_sync,看下打印結(jié)果:
2016-04-13 18:08:17.944 test[25521:1187204] 讀書===<NSThread: 0x7fe74ac05610>{number = 1, name = main}
2016-04-13 18:08:17.944 test[25521:1187204] 吃飯====<NSThread: 0x7fe74ac05610>{number = 1, name = main}
2016-04-13 18:08:17.945 test[25521:1187204] 上廁所====<NSThread: 0x7fe74ac05610>{number = 1, name = main}
可以看出,無論隊列的方式是串行隊列還是并行隊列,dispatch_sync同步操作方式都是不會創(chuàng)建新線程的,任務(wù)只會在主線程中執(zhí)行。
三、dispatch_get_global_queue():全局隊列
看下面一段代碼:
- (void) globalQueue
{
//全局隊列,都在主線程中執(zhí)行,不會死鎖,
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSLog(@"讀書===%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"吃飯====%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"上廁所====%@", [NSThread currentThread]);
});
}
結(jié)果:
2016-04-13 18:16:18.646 test[25609:1191848] 吃飯====<NSThread: 0x7f91c940db00>{number = 3, name = (null)}
2016-04-13 18:16:18.650 test[25609:1191841] 讀書===<NSThread: 0x7f91c9659890>{number = 2, name = (null)}
2016-04-13 18:16:18.646 test[25609:1191855] 上廁所====<NSThread: 0x7f91c940fa50>{number = 4, name = (null)}
全局隊列是系統(tǒng)的,無序創(chuàng)建,直接用即可,可以看出,全局隊列與并行隊列類型,但是調(diào)試時,無法確認操作所在隊列。
當(dāng)操作方式為dispatch_sync時,不再做解析,雷同上面。
四、dispatch_get_main_queue():主隊列
看下面一段代碼:
- (void) mainQueue
{
//直接死鎖
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
NSLog(@"讀書===%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"吃飯====%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"上廁所====%@", [NSThread currentThread]);
});
}
結(jié)果:
2016-04-13 18:35:50.259 test[25749:1204150] 讀書===<NSThread: 0x7fc9f8e05c30>{number = 1, name = main}
2016-04-13 18:35:50.264 test[25749:1204150] 吃飯====<NSThread: 0x7fc9f8e05c30>{number = 1, name = main}
2016-04-13 18:35:50.264 test[25749:1204150] 上廁所====<NSThread: 0x7fc9f8e05c30>{number = 1, name = main}
每一個應(yīng)用程序中只有一個主隊列,直接使用即可無需創(chuàng)建,常常在主隊列中更新UI。主隊列中的操作都應(yīng)該自主隊列中執(zhí)行,不存在異步的概念。除非主線程被用戶殺掉,否則永遠不會結(jié)束。
五、dispatch_sync的應(yīng)用場景(登陸操作)。dispatch_sync會阻塞并行隊列的執(zhí)行,要求某一操作執(zhí)行完成之后才會執(zhí)行下一個操作。
- (void) newThread
{
dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_CONCURRENT);
__block BOOL logon = NO;
dispatch_sync(q, ^{ //同步
NSLog(@"模擬耗時操作 %@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:2.0f];//停留兩秒鐘,模仿耗時操作
NSLog(@"模擬耗時完成 %@", [NSThread currentThread]);
logon = YES;
});
dispatch_async(q, ^{
NSLog(@"登錄完成的處理 %@", [NSThread currentThread]);
});
}
結(jié)果:
2016-04-14 10:47:24.117 test[26976:1276763] 模擬耗時操作 <NSThread: 0x7fe3a8d054e0>{number = 1, name = main}
2016-04-14 10:47:26.119 test[26976:1276763] 模擬耗時完成 <NSThread: 0x7fe3a8d054e0>{number = 1, name = main}
2016-04-14 10:47:26.119 test[26976:1276894] 登錄完成的處理 <NSThread: 0x7fe3a8c10f80>{number = 2, name = (null)}
六、dispatch_barrier_async,在并行隊列中等待前面的操作執(zhí)行完成后,才恢復(fù)后面的執(zhí)行狀態(tài)。
- (void) dispatchBarrierAsync
{
dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue, ^(){
NSLog(@"%@====dispatch-1", [NSThread currentThread]);
});
dispatch_async(concurrentQueue, ^(){
NSLog(@"%@=====dispatch-2", [NSThread currentThread]);
});
dispatch_barrier_async(concurrentQueue, ^(){
NSLog(@"%@======dispatch-barrier", [NSThread currentThread]);
});
dispatch_async(concurrentQueue, ^(){
NSLog(@"%@======dispatch-3", [NSThread currentThread]);
});
dispatch_async(concurrentQueue, ^(){
NSLog(@"%@======dispatch-4", [NSThread currentThread]);
});
}
結(jié)果:
2016-04-14 11:00:34.769 test[27143:1285750] <NSThread: 0x7ff80a70adb0>{number = 3, name = (null)}=====dispatch-2
2016-04-14 11:00:34.769 test[27143:1285758] <NSThread: 0x7ff80a40f460>{number = 2, name = (null)}====dispatch-1
2016-04-14 11:00:34.772 test[27143:1285758] <NSThread: 0x7ff80a40f460>{number = 2, name = (null)}======dispatch-barrier
2016-04-14 11:00:34.772 test[27143:1285758] <NSThread: 0x7ff80a40f460>{number = 2, name = (null)}======dispatch-3
2016-04-14 11:00:34.772 test[27143:1285750] <NSThread: 0x7ff80a70adb0>{number = 3, name = (null)}======dispatch-4
七、dispatch_group_t,當(dāng)有多個任務(wù)時,可以把多個任務(wù)放到group里面,group執(zhí)行完畢后再執(zhí)行其他任務(wù)。
- (void) group
{
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
NSLog(@"task1 begin=====%@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"task2 begin=====%@", [NSThread currentThread]);
});
dispatch_group_notify(group, queue, ^{
NSLog(@"======================%@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"task3 begin=====%@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"task4 begin=====%@", [NSThread currentThread]);
});
}
結(jié)果:
2016-04-14 11:35:54.676 test[27339:1300173] task1 begin=====<NSThread: 0x7fe3da606170>{number = 2, name = (null)}
2016-04-14 11:35:54.729 test[27339:1300202] task4 begin=====<NSThread: 0x7fe3da621660>{number = 5, name = (null)}
2016-04-14 11:35:54.729 test[27339:1300167] task2 begin=====<NSThread: 0x7fe3da6213a0>{number = 3, name = (null)}
2016-04-14 11:35:54.729 test[27339:1300178] task3 begin=====<NSThread: 0x7fe3da51f7b0>{number = 4, name = (null)}
2016-04-14 11:35:54.770 test[27339:1300178] ======================<NSThread: 0x7fe3da51f7b0>{number = 4, name = (null)}
可以看出,當(dāng)所有任務(wù)都執(zhí)行完畢后才執(zhí)行dispatch_group_notify中的任務(wù)。
看完這篇文章,相信大家對GCD有了詳細的了解,有問題歡迎大家一起探討,下班回家吃飯去,哈哈。