【原创】GCD编程 - 2

上一篇讲了一下GCD的基本用法,这一篇稍微升华一下,说说关于GCD编程中‘同步’的那些事儿。

先看一下原型:

-(void) asyncMethodForPrint:(NSString *) ch{
    NSLog(@"asyncMethodForPrint[%@]", ch);
}

-(void) test
{
    NSArray *arr = [NSArray arrayWithObjects:@"a",@"b",@"c",@"d",@"e",@"f",@"g",nil];
    
    for (NSString *item in arr) {
        
        [self asyncMethodForPrint:item];
    }
}

显然上面是按a~g的顺序进行日志输出,那么对于一个多核移动设备,充分利用起咱们的cpu的一种形式是什么呢?当然是用GCD来弄了,通过GCD,通常系统自己维护一个work线程池,当有task需要被执行的时候,从线程池中‘拿’一个出来直接就能用,因此上面的代码,在GCD编程的方式下,并发执行的形式为:

-(void) asyncMethodForPrint:(NSString *) ch{
    NSLog(@"asyncMethodForPrint[%@]", ch);
}

-(void) test
{
    NSArray *arr = [NSArray arrayWithObjects:@"a",@"b",@"c",@"d",@"e",@"f",@"g",nil];

    for (NSString *item in arr) {

        dispatch_async(dispatch_get_global_queue(0, 0ul), ^{
            [self asyncMethodForPrint:item];
        });
    }
}

很简单,至此,我们还是稍稍重复了上一篇所讲的内容,当然,日志不会再按顺序输出了,而是:

2013-06-25 18:23:47.171 GCDExample[4318:1303] asyncMethodForPrint[a]
2013-06-25 18:23:47.171 GCDExample[4318:3d07] asyncMethodForPrint[d]
2013-06-25 18:23:47.175 GCDExample[4318:1303] asyncMethodForPrint[e]
2013-06-25 18:23:47.175 GCDExample[4318:3d07] asyncMethodForPrint[f]
2013-06-25 18:23:47.171 GCDExample[4318:1e03] asyncMethodForPrint[c]
2013-06-25 18:23:47.171 GCDExample[4318:1c03] asyncMethodForPrint[b]
2013-06-25 18:23:47.176 GCDExample[4318:1303] asyncMethodForPrint[g]

关于wait

 

那么,现在问题来了,我们目前的任务仅仅是print一个个独立无关联的字符串,当然可以通过concurrent队列走并发的形式了,但如果业务变了,俺们需要在for循环后面打印asyncMethodForPrint方法执行的次数: 

static int counter = 0;

-(void) asyncMethodForPrint:(NSString *) ch{
    NSLog(@"asyncMethodForPrint[%@]", ch);
    counter++;
}

-(void) test
{
    NSArray *arr = [NSArray arrayWithObjects:@"a",@"b",@"c",@"d",@"e",@"f",@"g",nil];

    for (NSString *item in arr) {

        dispatch_async(dispatch_get_global_queue(0, 0ul), ^{
            [self asyncMethodForPrint:item];
        });
    }
    
    NSLog(@"count: %d", counter);
}

悲剧了,count打印的结果不是0,就是1 ,因为dispatch_async会立即返回。如何解决这个问题,思路是:输出count之前,等待前面所有的task完结。那么需要引入group的概念,

修改后代码为:

static int counter = 0;

-(void) asyncMethodForPrint:(NSString *) ch{
  // 这里主要还是为了引入group,更严谨些,需要引入dispatch_semaphore_signal NSLog(
@"asyncMethodForPrint[%@]", ch); counter++; } -(void) test { NSArray *arr = [NSArray arrayWithObjects:@"a",@"b",@"c",@"d",@"e",@"f",@"g",nil]; // 创建一个group dispatch_group_t group_1 = dispatch_group_create(); for (NSString *item in arr) { // 将需要聚集执行的task作为group形式执行 dispatch_group_async(group_1, dispatch_get_global_queue(0, 0ul), ^{ [self asyncMethodForPrint:item]; }); } dispatch_group_wait(group_1, DISPATCH_TIME_FOREVER); dispatch_release(group_1); // 上面两句也可以写成: // dispatch_group_notify(group_1, dispatch_get_global_queue(0, 0ul), ^{ // NSLog(@"count: %d", counter); // }); // 这样牛逼之处在于它还能异步执行。。。尽管这个语句看来意义不大 NSLog(@"count: %d", counter); }

就是他了,上面的代码,如果了解分布式计算的同学,是不是感觉跟‘Map Reduce’相似?呵呵。

那么,可以看到通过引入dispatch_group_t,能给我们带来一些‘同步’的实现,相关的api还有dispatch_group_wait,请自行查阅Lib Doc。

GCD还有一些api,比如semaphore信号量、dispatch source、异步io等,平时用的机会也不是很多,暂不做深入学习,也许将来有篇GCD - 3那就说明真用到了。

posted on 2013-06-25 19:58  chenxi_tales  阅读(498)  评论(2编辑  收藏  举报