美文网首页
GCD 常用总结

GCD 常用总结

作者: panzhangbao | 来源:发表于2017-05-11 10:02 被阅读31次

什么是GCD?

  • GCD全称为Grand Central Dispatch,是libdispatch的市场名称,而libdispatch是Apple的一个库,其为并发代码在iOS和OS X的多核硬件上执行提供支持。
  • 确切地说GCD是一套低层级的C API,通过 GCD,开发者只需要向队列中添加一段代码块(block或C函数指针),而不需要直接和线程打交道。
  • GCD在后端管理着一个线程池,它不仅决定着你的代码块将在哪个线程被执行,还根据可用的系统资源对这些线程进行管理。
  • 这样通过GCD来管理线程,从而解决线程被创建的问题。

GCD的优势

  • 易用: GCD 提供一个易于使用的并发模型而不仅仅只是锁和线程,以帮助我们避开并发陷阱,而且因为基于block,它能极为简单得在不同代码作用域之间传递上下文。
  • 灵活: GCD 具有在常见模式上(比如锁、单例),用更高性能的方法优化代码,而且GCD能提供更多的控制权力以及大量的底层函数。
  • 性能: GCD能自动根据系统负载来增减线程数量,这就减少了上下文切换以及增加了计算效率。

主队列

  • 与主线程功能相同。实际上,提交至main queue的任务会在主线程中执行。

  • main queue可以调用dispatch_get_main_queue()来获得。因为main queue是与主线程相关的,所以这是一个串行队列。和其它串行队列一样,这个队列中的任务一次只能执行一个。它能保证所有的任务都在主线程执行,而主线程是唯一可用于更新 UI 的线程。

    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    dispatch_async(mainQueue, ^{
        NSLog(@"异步主队列");
    });

全局队列

  • 全局队列是系统提供的可以直接调用的队列,用户不需要创建,可以通过dispatch_get_global_queue这个方法来调用它们。
  • 系统为每个程序提供了四种全局队列,这些队列中仅仅通过优先级加以区别,这四种类型分别是高、中(默认)、低、后台。
    /** long identifier
     * {
     *    DISPATCH_QUEUE_PRIORITY_HIGH
     *    DISPATCH_QUEUE_PRIORITY_DEFAULT
     *    DISPATCH_QUEUE_PRIORITY_LOW
     *    DISPATCH_QUEUE_PRIORITY_BACKGROUND
     * }
     */
    dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    dispatch_sync(defaultQueue, ^{
        NSLog(@"同步全局队列");
    });
    ```

# 创建队列
      
- 我们还可以根据个人具体情况创建属于自己的队列。
- 创建队列有串行队列和并行队列两种,其中串行队列只能单线程操作,并行队列可以多线程操作。
- 而它们的执行方式也有两种:同步执行和异步执行。

// 1. 创建串行队列
dispatch_queue_t createSerialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
// 同步执行
dispatch_sync(createSerialQueue, ^{
NSLog(@"创建串行同步队列");
});
// 2. 创建并行队列
dispatch_queue_t createConcurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
// 异步执行
dispatch_async(createConcurrentQueue, ^{
NSLog(@"创建并行队列");
});

// 挂起队列
dispatch_suspend(createSerialQueue);
// 重挂队列
dispatch_resume(createSerialQueue);
// 变更优先级
dispatch_set_target_queue(createSerialQueue, defaultQueue);
```

单例操作 - 只执行一次的代码块

  • 这种方式适合登录、注册等一次性操作,或者应用到静态数据的加载
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"只运行一次哦");
    });

延时加载

    // 延时 2 秒
    double delayInSeconds = 2.0;
    // 相对时间
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds);
    // 绝对时间
//    popTime = [self getDispatchTimeByDate:[NSDate date]];
     dispatch_after(popTime, mainQueue, ^{
         NSLog(@"延时 2 s 执行");
     });

/*
 *  获取绝对时间
 */
- (dispatch_time_t)getDispatchTimeByDate:(NSDate *)date
{
    double second = 0.0;
    struct timespec timespec;

    NSTimeInterval interval = [date timeIntervalSinceNow];
    
    timespec.tv_sec = second;
    timespec.tv_nsec = modf(interval, &second) * NSEC_PER_SEC;
    
    return dispatch_walltime(&timespec, 0);
}

队列组 - 多个依赖关系

  • 队列组可以添加多个队列到队列中,而且按添加顺序执行,也相当于多个依赖关系吧
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_enter(group);
    dispatch_group_async(group, defaultQueue, ^{
        NSLog(@"执行调度组1");
    });
    dispatch_group_async(group, defaultQueue, ^{
        NSLog(@"执行调度组2");
    });
    dispatch_group_async(group, defaultQueue, ^{
        NSLog(@"执行调度组3");
    });
    // 只要属于 Dispatch Group 的处理尚未执行结束,就会一直等待,中途不能取消
//    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    
    dispatch_group_notify(group, mainQueue, ^{
        NSLog(@"后期添加的 group 队列,在 group 最后执行");
    });
    ```
# 单个依赖关系 - 推荐使用
dispatch_async(defaultQueue, ^{
    NSLog(@"先执行我");
});
// 在前面的任务执行结束后它才执行,而且它后面的任务等待其执行完后再执行
dispatch_barrier_async(defaultQueue, ^{
    NSLog(@"我是中间执行者哦");
});
dispatch_async(defaultQueue, ^{
    NSLog(@"最后执行者");
});
# 同步信号量

- dispatch_semaphore_signal是发送一个信号,自然会让信号总量加1,
- dispatch_semaphore_wait等待信号,当信号总量少于0的时候就会一直等待,否则就可以正常的执行,并让信号总量-1,根据这样的原理,我们便可以快速的创建一个并发控制来同步任务和有限资源访问控制
dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);
for (int i = 0; i < 10; i++)
{
    // 申请信号量
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    dispatch_group_async(group, defaultQueue, ^{
        NSLog(@"申请信号量:%i",i);
        sleep(2);
        // 释放信号量
        dispatch_semaphore_signal(semaphore);
        NSLog(@"释放信号量:%i", i);
    });
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
# 多个添加队列
// 注意,添加的这 10 个队列同步执行,并等待 queue 全部处理执行结束
unsigned int applyTimes = 5;
dispatch_apply(applyTimes, defaultQueue, ^(size_t i) {
    NSLog(@"添加的队列:%zu", i);
});
**个人建议:苹果自己开发或者多人协作开发用 GCD 就足够了,当设计到多个依赖关系时,可以考虑使用 NSOperation 。**
# 参考
[GCD使用三部曲之:基本用法](http://www.jianshu.com/p/d56064507fb8)

相关文章

  • GCD 常用总结

    什么是GCD? GCD全称为Grand Central Dispatch,是libdispatch的市场名称,而l...

  • GCD常用总结

    前言:从毕业到这家公司实习转正已经有一年多了,iOS开发这条路感觉真不好走,不管怎么样还得坚持学习,希望能和大家一...

  • GCD常用总结

    线程通讯 一次性代码 延迟执行 栅栏函数 (void)viewDidLoad {[super viewDidLoa...

  • iOS-GCD常用函数和栅栏函数

    GCD常用函数 GCD栅栏函数

  • iOS多线程GCD使用及总结

    这篇文章对iOS的多线程技术GCD的常用方法做了总结另一篇NSOperation在这里本文代码 - GCD: 简介...

  • GCD常用方法总结

    常用操作// 1.后台执行: //2. 主线程执行: //3. 一次性执行: //4. 延迟2秒执行: 其他高级用...

  • GCD常用API总结

    工作中,或者是看源码的过程中总是离不开GCD的,所以总结一下方便查阅。 void dispatch_barrier...

  • GCD常用方法总结

    GCD是异步执行任务的技术支之一,开发者只需要将想要执行的block任务添加到适当的Dispatch Queue(...

  • 十一、ios线程调用学习

    常用线程方式:GCD 一、GCD学习 Grand Central Dispatch(GCD) 是 Apple 开发...

  • OC 多线程:NSThread,GCD,NSOperation

    OC 常用的多线程实现方法有: NSThread GCD NSOperation 下面逐一总结一下。 NSThre...

网友评论

      本文标题:GCD 常用总结

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