GCD的基本思想
-
GCD的基本思想是将操作放在队列中去执行
(1)操作使用block定义。
(2)队列负责调度任务执行所在的线程以及具体的执行时间。
(3)队列的特点是先进先出,新添加到队列的操作排在最后。
-
队列 dispatch_queue_t
(1) DISPATCH_QUEUE_SERIAL:串行队列,队列中的任务只会顺序执行。
(2) DISPATCH_QUEUE_CONCURRENT:并行队列,队列中的任务通常会并发执行。
-
操作
dispatch_async 异步操作,会并发执行,不会顺序执行。
dispatch_sync 同步操作,会依次顺序执行,能决定任务执行的顺序。
一、DISPATCH_QUEUE_SERIAL: 串行队列:
- (void) GCD
{
//DISPATCH_QUEUE_SERIAL串行队列,会死锁,但是会执行嵌套同步操作之前的代码
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)}
可以看出来当操作方式是dispatch_async时,只有两个队列,一个主线程,一个子线程,在子线程中执行三个方法,所以异步操作是可以创建新线程的,而且操作会顺序执行的,这个非常有用,既不会影响主线程,又可以开启新线程按顺序执行任务。现在把操作方式改为dispatch_sync看一下打印结果:
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试试,看下打印结果:
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)}
首先,可以看出,当队列的属性是DISPATCH_QUEUE_CONCURRENT时,任务会无序执行的,而且并行队列DISPATCH_QUEUE_CONCURRENT是可以开启新线程的。
得出结果当队列的属性是DISPATCH_QUEUE_CONCURRENT并行队列,操作是异步操作dispatch_async时,会创建多个线程,操作无序执行。但是如果队列钱有其他任务,会等待其他任务执行完成后再执行其他的任务。适合的操作为:既不影响主线程,又不需要顺序执行的操作。
然后,我们再把操作改为dispatch_sync,看下打印结果:
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同步操作方式都是不会创建新线程的,任务只会在主线程中执行。
三、dispatch_get_global_queue():全局队列
看下面一段代码:
- (void) globalQueue
{
//全局队列,都在主线程中执行,不会死锁,
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]);
});
}
结果:
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)}
全局队列是系统的,无序创建,直接用即可,可以看出,全局队列与并行队列类型,但是调试时,无法确认操作所在队列。
当操作方式为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]);
});
}
结果:
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}
每一个应用程序中只有一个主队列,直接使用即可无需创建,常常在主队列中更新UI。主队列中的操作都应该自主队列中执行,不存在异步的概念。除非主线程被用户杀掉,否则永远不会结束。
五、dispatch_sync的应用场景(登陆操作)。dispatch_sync会阻塞并行队列的执行,要求某一操作执行完成之后才会执行下一个操作。
- (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]);
});
}
结果:
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,在并行队列中等待前面的操作执行完成后,才恢复后面的执行状态。
- (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]);
});
}
结果:
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,当有多个任务时,可以把多个任务放到group里面,group执行完毕后再执行其他任务。
- (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]);
});
}
结果:
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)}
可以看出,当所有任务都执行完毕后才执行dispatch_group_notify中的任务。
看完这篇文章,相信大家对GCD有了详细的了解,有问题欢迎大家一起探讨,下班回家吃饭去,哈哈。