GCD系列:队列(queue)

GCD是基于C封装的函数,具备非常高的效率,在ARC环境下,无须主动管理内存,无须dispatch_retain和dispatch_release,可以将重点关注在业务逻辑上。
GCD是基于队列的封装,下面浅要解析GCD的队列。

GCD获取线程的方式

  • void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);获取一个异步线程队列,queue用于指定block执行体所在的队列
  • void dispatch_sync_f(dispatch_queue_t queue,void *_Nullable contex,dispatch_function_t work); 跟dispatch_sync类似,只不过接收的是一个dispatch_function_t的函数。
  • void dispatch_async(dispatch_queue_t queue, dispatch_block_t block); 获取一个异步线程,接收一个闭包block.
  • void dispatch_async_f(dispatch_queue_t queue,void *_Nullable context,dispatch_function_t work);获取一个异步线程,接收一个函数指针.

GCD获取队列的方式

  • dispatch_queue_t dispatch_get_main_queue() //获取主队列
  • dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags); //获取全局队列,由系统分配,分配完成后不可更改,flags是预留字段,传递任何非0值将返回一个NULL值引发异常,identifier指定全局队列的级别,队列的级别如下:
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN

推荐使用基于QOS_CLASS的属性级别.

QOS_CLASS_USER_INTERACTIVE  //最高优先级,用于UI更新等与用户交互的操作.
QOS_CLASS_USER_INITIATED        //初始化优先级,用于初始化等,等同于DISPATCH_QUEUE_PRIORITY_HIGH
QOS_CLASS_DEFAULT                   //默认优先级,等同于DISPATCH_QUEUE_PRIORITY_DEFAULT
QOS_CLASS_UTILITY                     //低优先级,等同于DISPATCH_QUEUE_PRIORITY_LOW
QOS_CLASS_BACKGROUND         //后台级,用户用户无法感知的一些数据处理,等同于DISPATCH_QUEUE_PRIORITY_BACKGROUND
  • 自己创建的队列.dispatch_queue_t dispatch_queue_create(const char *_Nullable label,dispatch_queue_attr_t _Nullable attr);label表示该队列的唯一标识字符串,可以使用const char *dispatch_queue_get_label(dispatch_queue_t _Nullable queue);来获取该字符串,参数二attr指定队列的执行顺序,有以下参数:
DISPATCH_QUEUE_SERIAL                 //指定串行(FIFO)队列,等同于传入参数NULL
DISPATCH_QUEUE_CONCURRENT    //指定并发队列,
dispatch_queue_attr_t dispatch_queue_attr_make_with_qos_class(dispatch_queue_attr_t _Nullable attr,dispatch_qos_class_t qos_class, int relative_priority);产生一个基于QOS_CLASS的队列.

dispatch_apply应用

dispatch_apply必须要结合dispatch_async 或者dispatch_async_f函数一起使用,如果脱离了dispatch_async函数,程序很容易crash,需要特别关注.
在指定的queue中去直接执行dispatch_appl(count,queue,block);会直接引发crash!

  • void dispatch_apply(size_t iterations, dispatch_queue_t queue,DISPATCH_NOESCAPE void (^block)(size_t));
    应用一个block,执行block代码块iterations次,每次执行的index通过size_t参数传递到block代码块内部
    queue:指定apply函数接收的闭包block执行对应的队列方式,如果是串行队列,跟for循环功能一致,无法达到优化性能的目的。
    如果是并行队列,则重复执行block的顺序不定,以达到优化性能的目的,下面是2个简单的例子:

    ####case 1:

    void dispatchApply() {
    
      dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
      dispatch_async(dispatch_get_main_queue(), ^{
    
          //执行的顺序取决于queue是串行还是并行,如果使用串行就跟for循环一样,没有意义
          //Dispatch_apply函数主要的功能是提高性能.
          dispatch_apply(10, queue, ^(size_t index) {
    
              NSLog(@"index....%lu",index);
          });
          //dispatch_apply是串行执行,知道10次invoke complete的时候,才继续往下执行.
          NSLog(@"ddddd");
      });
    }
    输出结果:  **可以看出,是并行执行的,达到了apply优化性能的目的.**
    2017-02-27 14:56:03.856182 dispatch_queue[3154:130315] index....0
    2017-02-27 14:56:03.856182 dispatch_queue[3154:130336] index....2
    2017-02-27 14:56:03.856205 dispatch_queue[3154:130337] index....1
    2017-02-27 14:56:03.856240 dispatch_queue[3154:130315] index....4
    2017-02-27 14:56:03.856251 dispatch_queue[3154:130336] index....5
    2017-02-27 14:56:03.856208 dispatch_queue[3154:130335] index....3
    2017-02-27 14:56:03.856272 dispatch_queue[3154:130315] index....6
    2017-02-27 14:56:03.856278 dispatch_queue[3154:130336] index....8
    2017-02-27 14:56:03.856280 dispatch_queue[3154:130337] index....7
    2017-02-27 14:56:03.856293 dispatch_queue[3154:130335] index....9
    2017-02-27 14:56:03.856327 dispatch_queue[3154:130315] ddddd

    ####case 2:

    void dispatchApplySerial() {
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
    
        //执行的顺序取决于queue是串行还是并行,如果使用串行就跟for循环一样,没有意义
        //Dispatch_apply函数主要的功能是提高性能.
        dispatch_apply(10, queue, ^(size_t index) {
    
            NSLog(@"index....%lu",index);
        });
        //dispatch_apply是串行执行,知道10次invoke complete的时候,才继续往下执行.
        NSLog(@"ddddd");
    });
    }
    
    输出结果:  
    2017-02-27 14:53:40.472788 dispatch_queue[3096:128184] index....0
    2017-02-27 14:53:40.472830 dispatch_queue[3096:128184] index....1
    2017-02-27 14:53:40.472842 dispatch_queue[3096:128184] index....2
    2017-02-27 14:53:40.472851 dispatch_queue[3096:128184] index....3
    2017-02-27 14:53:40.472860 dispatch_queue[3096:128184] index....4
    2017-02-27 14:53:40.472868 dispatch_queue[3096:128184] index....5
    2017-02-27 14:53:40.472877 dispatch_queue[3096:128184] index....6
    2017-02-27 14:53:40.472885 dispatch_queue[3096:128184] index....7
    2017-02-27 14:53:40.472893 dispatch_queue[3096:128184] index....8
    2017-02-27 14:53:40.472902 dispatch_queue[3096:128184] index....9
    2017-02-27 14:53:40.472931 dispatch_queue[3096:128223] ddddddddd
  • void dispatch_apply_f(size_t iterations, dispatch_queue_t queue,void *_Nullable context,void (work)(void _Nullable, size_t));
    跟dispatch_apply功能一致,方法接收一个函数指针.

void dispatch_set_target_queue(dispatch_object_t object,dispatch_queue_t _Nullable queue);

dispatch_set_target_queue可以将object指向的dispatch_object_t对象的队列方式按照参数2的queue的队列方式去执行,它的一大功能就是可以把并发的函数变为串行执行,下面是例子:

void setTargetQueue() {
    
    dispatch_queue_t _serialQueue = dispatch_queue_create("this.is.serial.queue", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t _concurrcyQueue = dispatch_queue_create("this.is.concurrency.queue", DISPATCH_QUEUE_CONCURRENT);
//  dispatch_set_target_queue(_concurrcyQueue,_serialQueue);
    NSInteger index = 0;
    while (index ++ < 5) {
        
        dispatch_async(_concurrcyQueue, ^{ NSLog(@"11111111111"); });
        dispatch_async(_concurrcyQueue, ^{ NSLog(@"22222222222"); });
        dispatch_async(_serialQueue, ^{ NSLog(@"3333333333"); });
    }
}
//执行的结果如下:
2017-02-27 15:22:42.853347 dispatch_queue[3443:148056] 3333333333
2017-02-27 15:22:42.853346 dispatch_queue[3443:148077] 11111111111
2017-02-27 15:22:42.853367 dispatch_queue[3443:148069] 11111111111
2017-02-27 15:22:42.853375 dispatch_queue[3443:148057] 22222222222
2017-02-27 15:22:42.853437 dispatch_queue[3443:148056] 3333333333
2017-02-27 15:22:42.853475 dispatch_queue[3443:148077] 22222222222
2017-02-27 15:22:42.853482 dispatch_queue[3443:148069] 11111111111
2017-02-27 15:22:42.853499 dispatch_queue[3443:148057] 22222222222
2017-02-27 15:22:42.853507 dispatch_queue[3443:148056] 3333333333
2017-02-27 15:22:42.853519 dispatch_queue[3443:148077] 11111111111
2017-02-27 15:22:42.853529 dispatch_queue[3443:148069] 22222222222
2017-02-27 15:22:42.853538 dispatch_queue[3443:148057] 11111111111
2017-02-27 15:22:42.853546 dispatch_queue[3443:148056] 3333333333
2017-02-27 15:22:42.853557 dispatch_queue[3443:148077] 22222222222
2017-02-27 15:22:42.853585 dispatch_queue[3443:148056] 3333333333
//可以看出,执行结果很混乱,属于并发执行,现在打开set_target_queue注释,得到以下结果:
2017-02-27 15:25:06.510355 dispatch_queue[3470:149395] 11111111111
2017-02-27 15:25:06.510405 dispatch_queue[3470:149395] 22222222222
2017-02-27 15:25:06.510423 dispatch_queue[3470:149395] 3333333333
2017-02-27 15:25:06.510438 dispatch_queue[3470:149395] 11111111111
2017-02-27 15:25:06.510452 dispatch_queue[3470:149395] 22222222222
2017-02-27 15:25:06.510465 dispatch_queue[3470:149395] 3333333333
2017-02-27 15:25:06.510477 dispatch_queue[3470:149395] 11111111111
2017-02-27 15:25:06.510491 dispatch_queue[3470:149395] 22222222222
2017-02-27 15:25:06.510501 dispatch_queue[3470:149395] 3333333333
2017-02-27 15:25:06.510512 dispatch_queue[3470:149395] 11111111111
2017-02-27 15:25:06.510524 dispatch_queue[3470:149395] 22222222222
2017-02-27 15:25:06.510536 dispatch_queue[3470:149395] 3333333333
2017-02-27 15:25:06.510548 dispatch_queue[3470:149395] 11111111111
2017-02-27 15:25:06.510560 dispatch_queue[3470:149395] 22222222222
2017-02-27 15:25:06.510575 dispatch_queue[3470:149395] 3333333333
这就是典型的dispatch_set_target并发变FIFO串行执行功能.

延时函数dispatch_after

  • void dispatch_after(dispatch_time_t when,dispatch_queue_t queue,dispatch_block_t block);
    1. 参数1 when指定block执行的时间,
    2. 参数2 queue指定block执行的队列形式,
    3. 参数3 block指定延时函数接收的闭包.
  • void dispatch_after_f(dispatch_time_t when,dispatch_queue_t queue,void *_Nullable context,dispatch_function_t work);
    1.跟dispatch_after功能一样.
    2.参数3 work指定延时函数接收一个函数指针.

Dispatch_barrier

dispatch_barrier在多线程编程中用来保证某个值域的原子性。在多线程操作中,同时对于同一个值的读取不会有问题,但如果同时对一个值进行修改就会产生冲突,此时dispatch_barrier可以很好的解决这个问题,dispatch_barrier就像一个盒子,当盒子内的任务没有出来前,盒子外的任务全部维护到一个队列中。
相关函数如下:

  • void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block);//将闭包放入同步环境的queue队列中执行.
  • void dispatch_barrier_sync_f(dispatch_queue_t queue,void *_Nullable context,dispatch_function_t work);//将函数放入同步环境中的queue执行
  • void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);//将闭包放入异步环境的queue队列中执行.
  • void dispatch_barrier_async_f(dispatch_queue_t queue,void *_Nullable context,dispatch_function_t work);//将函数放入异步环境中的queue执行
    事例代码如下:
NSMutableDictionary *_vars;
void setVars(NSMutableDictionary *vars) {
    
    dispatch_queue_t _serialQueue = dispatch_queue_create("this.is.serial.queue", DISPATCH_QUEUE_SERIAL);
    dispatch_barrier_async(_serialQueue, ^{
        
        _vars = vars;
    });
}

为一个队列添加属性和获取属性

GCD允许给一个队列通过特定的key值关联属性contenxt,有点类似于使用runtime的objc_associated,在类别中给一个类添加属性,用于实际业务需要.
当key对应的context发生变化时,会触发C函数destructor.

  • void dispatch_queue_set_specific(dispatch_queue_t queue, const void key,void _Nullable context, dispatch_function_t _Nullable destructor);
    //通过key,为一个queue设置context
  • void *_Nullable dispatch_queue_get_specific(dispatch_queue_t queue, const void *key);
    //通过key,从一个queue读取context
  • void *_Nullable dispatch_get_specific(const void *key);
    //测试当前队列是否是key对应的queue队列(有待认证。。)
    示例代码如下:
void destructorInvoke(const void *string) {
    
    NSLog(@"destructor ----->%@",[[NSString alloc] initWithUTF8String:(char *)string]);
}
dispatch_queue_t _serialQueue;
void dispatchSpecific() {
    
    setSpecific(@"1");
    setSpecific(@"2");
    setSpecific(@"3");
    setSpecific(@"4");
    setSpecific(@"5");
}
void setSpecific(NSString *context) {
    
    if (!_serialQueue) {
        
        _serialQueue = dispatch_queue_create("serial.queue", DISPATCH_QUEUE_SERIAL);
    }
    const char *key = "set one context";
    NSLog(@"set string:%@",context);
    dispatch_queue_set_specific(_serialQueue, key, context.UTF8String, &destructorInvoke);
    
    NSLog(@"context is : %@",[NSString stringWithUTF8String:dispatch_queue_get_specific(_serialQueue,key)]);
}
输出结果:
2017-02-27 16:14:25.026095 dispatch_queue[3855:177340] set string:1
2017-02-27 16:14:25.026151 dispatch_queue[3855:177340] context is : 1
2017-02-27 16:14:25.026166 dispatch_queue[3855:177340] set string:2
2017-02-27 16:14:25.026194 dispatch_queue[3855:177340] context is : 2
2017-02-27 16:14:25.026206 dispatch_queue[3855:177340] set string:3
2017-02-27 16:14:25.026212 dispatch_queue[3855:177396] destructor ----->1
2017-02-27 16:14:25.026225 dispatch_queue[3855:177340] context is : 3
2017-02-27 16:14:25.026228 dispatch_queue[3855:177396] destructor ----->2
2017-02-27 16:14:25.026241 dispatch_queue[3855:177340] set string:4
2017-02-27 16:14:25.026298 dispatch_queue[3855:177340] context is : 4
2017-02-27 16:14:25.026307 dispatch_queue[3855:177396] destructor ----->3
2017-02-27 16:14:25.026315 dispatch_queue[3855:177340] set string:5
2017-02-27 16:14:25.026335 dispatch_queue[3855:177340] context is : 5
2017-02-27 16:14:25.026338 dispatch_queue[3855:177396] destructor ----->4

博主已经开通了博客地址: kobeluo,哪里有更丰富的资源,欢迎与我交流。

转载于:https://www.cnblogs.com/KobeLuo/p/6473109.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值