zoukankan      html  css  js  c++  java
  • 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/

  • 相关阅读:
    基本技能训练之线程
    关于UEditor的使用配置(图片上传配置)
    PAT 乙级练习题1002. 写出这个数 (20)
    codeforces 682C Alyona and the Tree DFS
    codeforces 681D Gifts by the List dfs+构造
    codeforces 678E Another Sith Tournament 概率dp
    codeforces 680E Bear and Square Grid 巧妙暴力
    codeforces 678D Iterated Linear Function 矩阵快速幂
    codeforces 679A Bear and Prime 100 交互
    XTUOJ 1248 TC or CF 搜索
  • 原文地址:https://www.cnblogs.com/KobeLuo/p/6484827.html
Copyright © 2011-2022 走看看