iOS之浅谈GCD

作者: LuxDark | 来源:发表于2016-04-13 18:51 被阅读208次

    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有了详细的了解,有问题欢迎大家一起探讨,下班回家吃饭去,哈哈。

    相关文章

      网友评论

        本文标题:iOS之浅谈GCD

        本文链接:https://www.haomeiwen.com/subject/rizwlttx.html