GCD系列:调度组(dispatch_group)

Dispatch_group

GCD头文件group.h中谈到,可以将一组block提交到调度组(dispatch_group)中,执行逐个串行回调,下面来看看相关函数。


函数申明与理解

  • dispatch_group_t dispatch_group_create(void);
    //创建一个调度组,释放调度组使用dispatch_release()函数,创建成功返回一个dispatch_group调度组,失败则返回NULL.

  • void dispatch_group_async(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);
    //提交一个闭包函数(block)到queue中,并关联到指定的group调度组.通过typedef void (^dispatch_block_t)(void);我们可以发现,该函数无法给block传递参数.
    1. group 指定的调度组,block的关联调度组。
    2. queue 提交闭包函数(block)的队列。
    3. block 提交到指定queue的闭包函数block。

  • void dispatch_group_async_f(dispatch_group_t group,dispatch_queue_t queue,void *_Nullable context,dispatch_function_t work);
    //提交一个函数指针(dispatch_function_t)到queue中,并关联到指定的group调度组,函数返回void.
    1. group 指定的调度组,block的关联调度组。
    2. queue 提交闭包函数(block)的队列。
    3. context 传递到函数中的的参数。
    4. work 在指定的queue中的指定函数。

  • long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);
    //执行等待,等待所有关联到group调度组的block执行完成,或者等待timeout发生超时,当在超时时间timeout内执行完了所有的block函数,则返回0,否则返回非0值。
    1. group 给定调度组
    2. timeout 如果group调度组里边的block执行时间非常长,函数的等待时间.

  • void dispatch_group_notify(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);
    //该函数指定了一个block,当group调度组里边的所有block都执行完成时,将通知block关联到group中,并加入到给定的queue队列里,当group调度组当前没有任何block关联的时候将立即将block提交到queue队列,并与group调度组关联,该函数返回void.
    1. group 给定的调度组
    2. queue 给定的队列.
    3. 给定的闭包函数.

  • void dispatch_group_notify_f(dispatch_group_t group,dispatch_queue_t queue,void *_Nullable context,dispatch_function_t work);
    //与disptch_group_notify类似,提交的一个函数work作为执行体,context是执行时传递的参数,该函数返回void.

  • void dispatch_group_enter(dispatch_group_t group);
  • void dispatch_group_leave(dispatch_group_t group);
    //这一对函数调用一次意味着非使用dispatch_group_async方式,将一个block提交到指定的queue上并关联到group调度组.两个函数必须成对出现。


实际例子

  • 环境变量与函数
//create one group.
dispatch_group_t _group;
dispatch_queue_t _serialQ;
void dispatch_group_test() {
    
    _group = dispatch_group_create();
    _serialQ = dispatch_queue_create("this.is.a.serial.queue", DISPATCH_QUEUE_SERIAL);

    // one_test_function_use();
}

dispatch_group_test函数下面会继续提到,标记为“入口函数”

定义一个调度组_group和一个串行队列_serialQ,下面所有的测试函数都有效.

  • dispatch_group_async函数的使用实例
void dispatch_group_async_use() {

    void (^noParameterHandle)(void) = ^(void) {
        
        NSLog(@"execute block");
    };
    
    for (NSInteger index = 0; index < 5; index ++) {
        
        dispatch_group_async(_group, _serialQ,noParameterHandle);
    }
}

执行结果:
2017-03-01 17:33:23.809238 dispatch_data[17920:907260] execute block
2017-03-01 17:33:23.809343 dispatch_data[17920:907260] execute block
2017-03-01 17:33:23.809358 dispatch_data[17920:907260] execute block
2017-03-01 17:33:23.809371 dispatch_data[17920:907260] execute block
2017-03-01 17:33:23.809381 dispatch_data[17920:907260] execute block

可以从实例中看出,使用dispatch_group_async函数关联的block无法传递参数.

  • dispatch_group_async_f函数实践示例

先实现一个类型为void ()(void *)的C函数

void function_t_use(void *value) {
    
    char *cString = value;
    
    NSLog(@"value is : %@",[NSString stringWithUTF8String:cString]);
}      

下面是测试函数⤵️

void dispatch_group_async_f_use() {
    
    for (NSInteger index = 0; index < 5; index ++) {
        
        char *cString = (char *)[NSString stringWithFormat:@"%ld",index].UTF8String;
        
        dispatch_group_async_f(_group, _serialQ, cString, function_t_use);
    }
}
执行结果:
2017-03-01 18:00:39.641617 dispatch_data[18368:930399] value is : 0
2017-03-01 18:00:39.641656 dispatch_data[18368:930399] value is : 1
2017-03-01 18:00:39.641673 dispatch_data[18368:930399] value is : 2
2017-03-01 18:00:39.641688 dispatch_data[18368:930399] value is : 3
2017-03-01 18:00:39.641700 dispatch_data[18368:930399] value is : 4

dispatch_group_async_f_use 允许传递参数到function中,需要注意的是传递的参数尽量使用char ,测试时使用int 不能正确的得到结果.

  • long dispatch_group_wait(group,timeout) 函数实践示例
    当group关联的block实行完毕时 long = 0 属于正常情况,
void dispatch_group_waite_normal_use() {
    
    void (^noParameterHandle)(void) = ^(void) {
        
        NSLog(@"execute block");
    };
    
    dispatch_group_async(_group, _serialQ, noParameterHandle);
    
    NSLog(@"will waite...");
    
    long count = dispatch_group_wait(_group, dispatch_time(DISPATCH_TIME_NOW,10 * NSEC_PER_SEC));
    
    NSLog(@"count: %ld",count);
}
返回结果:
2017-03-01 18:21:39.823695 dispatch_data[18466:940513] will waite...
2017-03-01 18:21:39.823699 dispatch_data[18466:940543] execute block
2017-03-01 18:21:39.823762 dispatch_data[18466:940513] count: 0

可以看出,block注册到了_group中,属于异步函数,当前线程继续向下执行,打印willwaite...,之后调用dispatch_group_waite函数进入等待,由于单次block回调非常快,不会超过timeout的时间,最终打印count = 0,当timeout超时group还有关联的任务时,将返回非0值错误。

void dispatch_group_waite_timeout_use() {
    
    void (^noParameterHandle)(void) = ^(void) {
        
        sleep(1);
        NSLog(@"execute block");
    };
    
    for (NSUInteger index = 0; index < 5; index ++) {
        
        dispatch_group_async(_group, _serialQ, noParameterHandle);
    }
    
    NSLog(@"will waite...");
    
    long count = dispatch_group_wait(_group, dispatch_time(DISPATCH_TIME_NOW,3 * NSEC_PER_SEC));
    
    NSLog(@"count: %ld",count);
}
执行结果:
2017-03-01 18:31:02.762822 dispatch_data[18547:945276] will waite...
2017-03-01 18:31:03.767823 dispatch_data[18547:945310] execute block
2017-03-01 18:31:04.770983 dispatch_data[18547:945310] execute block
2017-03-01 18:31:05.763463 dispatch_data[18547:945276] count: 49
2017-03-01 18:31:05.772842 dispatch_data[18547:945310] execute block
2017-03-01 18:31:06.777980 dispatch_data[18547:945310] execute block
2017-03-01 18:31:07.779768 dispatch_data[18547:945310] execute block

该测试函数指定dispatch_group_wait函数的timeout是3秒,在执行完两次for循环后已经超时,最后得到的count值非0 count=49.
实际上该测试函数隐藏着一个值得讨论的地方:
在noParameterHandle这个闭包函数中,直接使用sleep(1),闭包执行的队列是_serialQ,
对于整个dispatch_group_waite_timeout_use函数,测试的时候是放在了mainQueue去执行,也就是dispatch_group_wait函数是在mainQueue中执行,此时跟闭包执行的队列不一致,各自在自己的队列执行,得到了上面的结果。

假设整个dispatch_group_waite_timeout_use函数的执行体所在的队列就是_serialQ,而闭包所在的队列也是_serialQ,所以就相当于6个task都提交到了_serialQ,task1代表dispatch_group_waite_timeout_use函数,task2..6代表noParameterHandle(有一个for循环),由于是串行执行,当代码执行到dispatch_group_wait函数时,整个_serialQ将进入等待,3秒之后,打印count值,之后再串行执行5个闭包task.
更换上面提到的“入口函数”,实践讨论的内容,代码如下:

void dispatch_group_test() {
    
    _group = dispatch_group_create();
    _serialQ = dispatch_queue_create("this.is.a.serial.queue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(_serialQ, ^{
        
        dispatch_group_waite_timeout_use();
    });
}
打印结果:
2017-03-01 18:36:26.547770 dispatch_data[18637:949068] will waite...
2017-03-01 18:36:29.549184 dispatch_data[18637:949068] count: 49
2017-03-01 18:36:30.550143 dispatch_data[18637:949068] execute block
2017-03-01 18:36:31.551091 dispatch_data[18637:949068] execute block
2017-03-01 18:36:32.552570 dispatch_data[18637:949068] execute block
2017-03-01 18:36:33.557777 dispatch_data[18637:949068] execute block
2017-03-01 18:36:34.562879 dispatch_data[18637:949068] execute block
  • void dispatch_group_notify(group,queue,block);函数实践示例
    当group所关联的block全部执行结束时,会立马将给定block关联到group中,并在给定的queue中执行.代码如下:
void dispatch_grout_notify_use() {
    
    void (^noParameterHandle)(void) = ^(void) {
        
        NSLog(@"execute block");
    };
    
    for (NSUInteger index = 0; index < 5; index ++) {
        
        dispatch_group_async(_group, _serialQ, noParameterHandle);
    }
    
    dispatch_group_notify(_group, _serialQ, ^{
        
        NSLog(@"executing the notify block...");
    });
}
执行结果:
2017-03-01 18:55:06.172181 dispatch_data[18706:955792] execute block
2017-03-01 18:55:06.172216 dispatch_data[18706:955792] execute block
2017-03-01 18:55:06.172229 dispatch_data[18706:955792] execute block
2017-03-01 18:55:06.172240 dispatch_data[18706:955792] execute block
2017-03-01 18:55:06.172249 dispatch_data[18706:955792] execute block
2017-03-01 18:55:06.172262 dispatch_data[18706:955792] executing the notify block...

由于dispatch_group_async是异步调用的,而dispatch_group_notify是同步调用的,所以,从该示例可以可以得到上述结论,dispatch_group_notify可以用于需要指定task之间的顺序时。

  • void dispatch_group_enter(group)与dispatch_group_leave(group);函数实践示例
    当你的代码无法使用dispatch_group_async函数去关联一个block到给定的调度组时,可以使用这对函数达到相同的功能.这里使用它来达到dispatch_group_async的功能,代码如下:
void dispatch_group_leave_enter_use() {
    
    void (^noParameterHandle)(void) = ^(void) {
        
        NSLog(@"execute block");
    };
    
    for (NSInteger index = 0; index < 5; index ++) {
        
        dispatch_group_enter(_group);
        dispatch_async(_serialQ, noParameterHandle);
        dispatch_group_leave(_group);
        //enter 和 leave 必须成对出现,否则会引发crash.
    }
}
执行结果:
2017-03-01 19:02:53.657501 dispatch_data[18739:958841] execute block
2017-03-01 19:02:53.657781 dispatch_data[18739:958841] execute block
2017-03-01 19:02:53.657803 dispatch_data[18739:958841] execute block
2017-03-01 19:02:53.657816 dispatch_data[18739:958841] execute block
2017-03-01 19:02:53.657827 dispatch_data[18739:958841] execute block

可以看出,当无法使用dispatch_group_async函数时,可以使用dispatch_group_enter和leave达到相同的效果.


dispatch_group主题功能介绍完毕,水平有限,为不误人子弟,如有错误之处,还请各位大神一定指出,在此谢过。

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

搭建博客方法:https://hexo.io/ http://liuhongjiang.github.io/hexotech/2012/11/21/how-to-build-blog/

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值