GCD(用法二)

GCD 队列组:dispatch_group

        有时候我们会有这样的需求:分别异步执行多个耗时任务,当多个耗时任务都执行完毕后,再回到指定线程执行任务。这时候我们可以用到 GCD 的队列组。调用队列组的dispatch_group_async先把任务放到队列中,然后将队列放入队列组中。或者使用队列组的dispatch_group_enter、dispatch_group_leave组合来实现。调用队列组的dispatch_group_notify回到指定线程执行任务;或者使用dispatch_group_wait回到当前线程继续向下执行(会阻塞当前线程)。

        放入线程组的任务执行完成了才会去调用dispatch_group_notify线程通知,而如果在任务中还嵌套了异步任务,线程组不会管这个嵌套异步任务是否执行完成,调用了这个任务就完成了,因为是异步的就不会等执行完成就继续下一步了,一旦线程组第一层的任务都执行完成了就会调用通知。如果将异步换成同步的,就要等待嵌套任务执行完成才会去通知。

dispatch_group_notify

监听 group 中任务的完成状态,当所有的任务都执行完成后,追加任务到 group 中,并执行任务。

- (void)groupNotify {

    NSLog(@"%@",[NSThread currentThread]);

    NSLog(@"begin");

    dispatch_group_t group = dispatch_group_create();

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_group_async(group, queue, ^{

        [NSThread sleepForTimeInterval:1];// 模拟耗时操作

        NSLog(@"111===%@",[NSThread currentThread]);

    });

    dispatch_group_async(group, queue, ^{

        [NSThread sleepForTimeInterval:1];// 模拟耗时操作

        NSLog(@"222===%@",[NSThread currentThread]);

    });

    dispatch_group_async(group, queue, ^{

        [NSThread sleepForTimeInterval:1];// 模拟耗时操作

        NSLog(@"333===%@",[NSThread currentThread]);

    });

    dispatch_group_notify(group, queue, ^{

        NSLog(@"notify");

        NSLog(@"notify===%@",[NSThread currentThread]);

    });

    NSLog(@"end");

}

输出结果:

2018-11-23 10:17:32.570579+0800 OC-Swift[1732:40516] <NSThread: 0x600002913000>{number = 1, name = main}

2018-11-23 10:17:32.570755+0800 OC-Swift[1732:40516] begin

2018-11-23 10:17:32.570865+0800 OC-Swift[1732:40516] end

2018-11-23 10:17:33.576228+0800 OC-Swift[1732:41373] 222===<NSThread: 0x600002966040>{number = 10, name = (null)}

2018-11-23 10:17:33.576246+0800 OC-Swift[1732:41374] 333===<NSThread: 0x600002996540>{number = 11, name = (null)}

2018-11-23 10:17:33.576227+0800 OC-Swift[1732:40796] 111===<NSThread: 0x600002990c40>{number = 8, name = (null)}

2018-11-23 10:17:33.576692+0800 OC-Swift[1732:41373] notify

2018-11-23 10:17:33.576988+0800 OC-Swift[1732:41373] notify===<NSThread: 0x600002966040>{number = 10, name = (null)}

结果分析:

当所有任务都执行完成之后,才执行dispatch_group_notify 中的任务。

在线程组中嵌套使用dispatch_async:

- (void)groupNotify {

    NSLog(@"%@",[NSThread currentThread]);

    NSLog(@"begin");

    dispatch_group_t group = dispatch_group_create();

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_group_async(group, queue, ^{

        dispatch_async(queue, ^{

            [NSThread sleepForTimeInterval:1];// 模拟耗时操作

            NSLog(@"111===%@",[NSThreadcurrentThread]);

        });

    });

    dispatch_group_async(group, queue, ^{

        dispatch_async(queue, ^{

            [NSThread sleepForTimeInterval:1];// 模拟耗时操作

            NSLog(@"222===%@",[NSThreadcurrentThread]);

        });

    });

    dispatch_group_async(group, queue, ^{

        dispatch_async(queue, ^{

            [NSThread sleepForTimeInterval:1];// 模拟耗时操作

            NSLog(@"333===%@",[NSThreadcurrentThread]);

        });

    });

    dispatch_group_notify(group, queue, ^{

        NSLog(@"notify");

        NSLog(@"notify===%@",[NSThread currentThread]);

    });

}

输出结果:

2018-11-23 10:54:36.377735+0800 OC-Swift[2129:57999] <NSThread: 0x6000019ab6c0>{number = 1, name = main}

2018-11-23 10:54:36.377940+0800 OC-Swift[2129:57999] begin

2018-11-23 10:54:36.378130+0800 OC-Swift[2129:58026] notify

2018-11-23 10:54:36.378367+0800 OC-Swift[2129:58026] notify===<NSThread: 0x6000019d50c0>{number = 3, name = (null)}

2018-11-23 10:54:37.383172+0800 OC-Swift[2129:58028] 222===<NSThread: 0x600001925f00>{number = 4, name = (null)}

2018-11-23 10:54:37.383191+0800 OC-Swift[2129:58025] 111===<NSThread: 0x600001928cc0>{number = 5, name = (null)}

2018-11-23 10:54:37.383249+0800 OC-Swift[2129:58027] 333===<NSThread: 0x600001925e40>{number = 6, name = (null)}

结果分析:

一旦线程组第一层的任务都执行完成了就会调用通知。

在线程组中嵌套使用dispatch_async:

- (void)groupNotify {

    NSLog(@"%@",[NSThread currentThread]);

    NSLog(@"begin");

    dispatch_group_t group = dispatch_group_create();

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_group_async(group, queue, ^{

        dispatch_sync(queue, ^{

            [NSThread sleepForTimeInterval:1];// 模拟耗时操作

            NSLog(@"111===%@",[NSThreadcurrentThread]);

        });

    });

    dispatch_group_async(group, queue, ^{

        dispatch_sync(queue, ^{

            [NSThread sleepForTimeInterval:1];// 模拟耗时操作

            NSLog(@"222===%@",[NSThreadcurrentThread]);

        });

    });

    dispatch_group_async(group, queue, ^{

        dispatch_sync(queue, ^{

            [NSThread sleepForTimeInterval:1];// 模拟耗时操作

            NSLog(@"333===%@",[NSThreadcurrentThread]);

        });

    });

    dispatch_group_notify(group, queue, ^{

        NSLog(@"notify");

        NSLog(@"notify===%@",[NSThread currentThread]);

    });

}

输出结果:

2018-11-23 10:57:56.254579+0800 OC-Swift[2168:59624] <NSThread: 0x600003e49340>{number = 1, name = main}

2018-11-23 10:57:56.254720+0800 OC-Swift[2168:59624] begin

2018-11-23 10:57:57.257480+0800 OC-Swift[2168:59659] 333===<NSThread: 0x600003ec83c0>{number = 5, name = (null)}

2018-11-23 10:57:57.257486+0800 OC-Swift[2168:59660] 111===<NSThread: 0x600003ec8380>{number = 3, name = (null)}

2018-11-23 10:57:57.257480+0800 OC-Swift[2168:59658] 222===<NSThread: 0x600003e2dd00>{number = 4, name = (null)}

2018-11-23 10:57:57.257756+0800 OC-Swift[2168:59658] notify

2018-11-23 10:57:57.257924+0800 OC-Swift[2168:59658] notify===<NSThread: 0x600003e2dd00>{number = 4, name = (null)}

结果分析:

必须要等待嵌套任务执行完成才会去通知。

dispatch_group_wait

暂停当前线程(阻塞当前线程),等待指定的 group 中的任务执行完成后,才会往下继续执行。或者等待timeout发生超时,当在超时时间timeout内执行完了所有的任务返回0,否则返回非0值。

- (void)groupWait {

    NSLog(@"%@",[NSThread currentThread]);

    NSLog(@"begin");

    dispatch_group_t group = dispatch_group_create();

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_group_async(group, queue, ^{

        [NSThread sleepForTimeInterval:1];// 模拟耗时操作

        NSLog(@"111===%@",[NSThread currentThread]);

    });

    dispatch_group_async(group, queue, ^{

        [NSThread sleepForTimeInterval:1];// 模拟耗时操作

        NSLog(@"222===%@",[NSThread currentThread]);

    });

    dispatch_group_async(group, queue, ^{

        [NSThread sleepForTimeInterval:1];// 模拟耗时操作

        NSLog(@"333===%@",[NSThread currentThread]);

    });

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

    NSLog(@"end");

}

输出结果:

2018-11-23 10:21:14.961247+0800 OC-Swift[1821:43835] <NSThread: 0x600002796900>{number = 1, name = main}

2018-11-23 10:21:14.961411+0800 OC-Swift[1821:43835] begin

2018-11-23 10:21:15.962678+0800 OC-Swift[1821:43871] 333===<NSThread: 0x6000027e9180>{number = 3, name = (null)}

2018-11-23 10:21:15.962694+0800 OC-Swift[1821:43872] 222===<NSThread: 0x6000027ec000>{number = 5, name = (null)}

2018-11-23 10:21:15.962720+0800 OC-Swift[1821:43870] 111===<NSThread: 0x6000027ea080>{number = 4, name = (null)}

2018-11-23 10:21:15.962990+0800 OC-Swift[1821:43835] end

结果分析:

当所有任务执行完成之后,才执行dispatch_group_wait之后的操作,会阻塞当前线程。

设定等待时间:

- (void)groupWait {

    NSLog(@"%@",[NSThread currentThread]);

    NSLog(@"begin");

    dispatch_group_t group = dispatch_group_create();

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_group_async(group, queue, ^{

        [NSThread sleepForTimeInterval:1];// 模拟耗时操作

        NSLog(@"111===%@",[NSThread currentThread]);

    });

    dispatch_group_async(group, queue, ^{

        [NSThread sleepForTimeInterval:1];// 模拟耗时操作

        NSLog(@"222===%@",[NSThread currentThread]);

    });

    dispatch_group_async(group, queue, ^{

        [NSThread sleepForTimeInterval:5];// 模拟耗时操作

        NSLog(@"333===%@",[NSThread currentThread]);

    });

    dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)));

    NSLog(@"end");

}

输出结果:

2018-11-23 11:12:06.774259+0800 OC-Swift[2329:65999] <NSThread: 0x600003236980>{number = 1, name = main}

2018-11-23 11:12:06.774379+0800 OC-Swift[2329:65999] begin

2018-11-23 11:12:07.777851+0800 OC-Swift[2329:66031] 222===<NSThread: 0x60000325df80>{number = 3, name = (null)}

2018-11-23 11:12:07.777851+0800 OC-Swift[2329:66032] 111===<NSThread: 0x60000325e380>{number = 4, name = (null)}

2018-11-23 11:12:09.775667+0800 OC-Swift[2329:65999] end

2018-11-23 11:12:11.778701+0800 OC-Swift[2329:66030] 333===<NSThread: 0x6000032b4b00>{number = 5, name = (null)}

结果分析:

当超过设定的等待时间后,就会执行dispatch_group_wait之后的操作,不会等待任务组中未执行完的任务执行完成。

需要注意的:dispatch_group_wait是同步的所以不能放在主线程执行。

dispatch_group_enter、dispatch_group_leave

dispatch_group_enter标志着一个任务追加到 group,执行一次,相当于 group 中未执行完毕任务数+1

dispatch_group_leave标志着一个任务离开了 group,执行一次,相当于 group 中未执行完毕任务数-1。

当 group 中未执行完毕任务数为0的时候,才会使dispatch_group_wait解除阻塞,或者执行追加到dispatch_group_notify中的任务。

- (void)groupEnterAndLeave{

     NSLog(@"%@",[NSThread currentThread]);

     NSLog(@"begin");

    dispatch_group_t group = dispatch_group_create();

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_group_enter(group);

    dispatch_async(queue, ^{

        [NSThread sleepForTimeInterval:1];

        NSLog(@"111===%@",[NSThread currentThread]);

        dispatch_group_leave(group);

    });

    dispatch_group_enter(group);

    dispatch_async(queue, ^{

        [NSThread sleepForTimeInterval:1];

        NSLog(@"222===%@",[NSThread currentThread]);

        dispatch_group_leave(group);

    });

    dispatch_group_enter(group);

    dispatch_async(queue, ^{

        [NSThread sleepForTimeInterval:1];

        NSLog(@"333===%@",[NSThread currentThread]);

        dispatch_group_leave(group);

    });

    dispatch_group_notify(group, queue, ^{

        NSLog(@"notify");

        NSLog(@"notify===%@",[NSThread currentThread]);

    });

    NSLog(@"end");

}

输出结果:

2018-11-23 14:34:24.784460+0800 OC-Swift[4127:148453] <NSThread: 0x600002bce880>{number = 1, name = main}

2018-11-23 14:34:24.784723+0800 OC-Swift[4127:148453] begin

2018-11-23 14:34:24.784877+0800 OC-Swift[4127:148453] end

2018-11-23 14:34:25.790320+0800 OC-Swift[4127:148487] 111===<NSThread: 0x600002b40040>{number = 5, name = (null)}

2018-11-23 14:34:25.790320+0800 OC-Swift[4127:148485] 222===<NSThread: 0x600002b40c00>{number = 4, name = (null)}

2018-11-23 14:34:25.790326+0800 OC-Swift[4127:148486] 333===<NSThread: 0x600002bbd080>{number = 3, name = (null)}

2018-11-23 14:34:25.790708+0800 OC-Swift[4127:148485] notify

2018-11-23 14:34:25.790986+0800 OC-Swift[4127:148485] notify===<NSThread: 0x600002b40c00>{number = 4, name = (null)}

结果分析:

当所有任务执行完成之后,才执行 dispatch_group_notify 中的任务。这里的dispatch_group_enter、dispatch_group_leave组合,其实等同于dispatch_group_async。

注意:如果使用上面两个函数,那么只有在任务管理组中的dispatch_group_enter和dispatch_group_leave都平衡的情况下dispatch_group_notify才会执行,它们一般是成对出现的, 进入一次就得离开一次。也就是说,当离开和进入的次数相同时,就代表任务组完成了。如果enter比leave多,那就是没完成,如果leave调用的次数多了, 会崩溃的。

在上面dispatch_group_notify的例子中,在线程组中嵌套使用dispatch_async,发现一旦线程组第一层的任务都执行完成了就会调用通知。这里dispatch_group_enter和dispatch_group_leave就派上用场了,它们可以确保等待嵌套任务执行完成才会去通知:

- (void)groupEnterAndLeave {

     NSLog(@"%@",[NSThread currentThread]);

     NSLog(@"begin");

    dispatch_group_t group = dispatch_group_create();

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_group_enter(group);

    dispatch_async(queue, ^{

        [NSThread sleepForTimeInterval:1];

        NSLog(@"111===%@",[NSThread currentThread]);

        dispatch_group_leave(group);

    });

    dispatch_group_enter(group);

    dispatch_group_async(group, queue, ^{

        dispatch_async(queue, ^{

            [NSThread sleepForTimeInterval:4];

            NSLog(@"222===%@",[NSThreadcurrentThread]);

            dispatch_group_leave(group);

        });

    });

    dispatch_group_enter(group);

    dispatch_async(queue, ^{

        [NSThread sleepForTimeInterval:1];

        NSLog(@"333===%@",[NSThread currentThread]);

        dispatch_group_leave(group);

    });

    dispatch_group_notify(group, queue, ^{

        NSLog(@"notify");

        NSLog(@"notify===%@",[NSThread currentThread]);

    });

    NSLog(@"end");

}

输出结果:

2018-11-23 15:59:05.550556+0800 OC-Swift[5031:183263] begin

2018-11-23 15:59:05.550672+0800 OC-Swift[5031:183263] end

2018-11-23 15:59:06.553207+0800 OC-Swift[5031:183299] 111===<NSThread: 0x60000153ed40>{number = 3, name = (null)}

2018-11-23 15:59:06.553207+0800 OC-Swift[5031:183296] 333===<NSThread: 0x60000153ec00>{number = 4, name = (null)}

2018-11-23 15:59:09.550970+0800 OC-Swift[5031:183298] 222===<NSThread: 0x600001531880>{number = 5, name = (null)}

2018-11-23 15:59:09.551351+0800 OC-Swift[5031:183299] notify

2018-11-23 15:59:09.551803+0800 OC-Swift[5031:183299] notify===<NSThread: 0x60000153ed40>{number = 3, name = (null)}

结果分析:

嵌套任务执行完成才会去通知。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容