美文网首页
GCD(用法二)

GCD(用法二)

作者: gpylove | 来源:发表于2018-11-23 16:03 被阅读14次

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)}

结果分析:

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

相关文章

  • GCD(用法二)

    GCD 队列组:dispatch_group 有时候我们会有这样的需求:分别异步执行多个耗时任务,当多个耗...

  • GCD和NSOperation实现多线程调用

    GCD: 打印结果: NSOperation:第一种基本用法: 打印结果: 第二种基本用法: 打印结果: 这种方法...

  • dispatch_group和dispatch_barrier的

    前天被人问到使用GCD做依赖的用法,结果完全答不上来,下来之后就搜索了一下GCD的高级用法,发现自己对于GCD的掌...

  • iOS面试--GCD常见用法

    项目中常见的GCD用法有已下几种: 1.GCD栅栏函数2.GCD快速迭代(遍历)3.GCD队列组的使用 1.GCD...

  • GCD

    iOS多线程 Swift4 GCD深入解析swift GCD 的一些高级用法GCD 之线程组(Dispatch G...

  • iOS - GCD中的定时器

    GCD定时器优点:① GCD定时器不受RunLoop约束② 比NSTimer更加准时。 GCD定时器用法敲 dis...

  • GCD用法简介

    GCD用法 GCD Dispatch Queue介绍 苹果官方对GCD的说明:开发者要做的只是定义想执行的任务并追...

  • iOS多线程

    iOS多线程实现方案 GCD(Grand Central Dispatch) 一、基本用法GCD会自动利用更多的C...

  • iOS多线程之GCD浅析

    本文用来介绍 iOS 多线程中 GCD 的相关知识以及使用方法,分析GCD的原理,总结GCD的用法和需要注意的地方...

  • iOS多线程之GCD用法详解

    在上一篇讲解了iOS开发的三种多线程实现方式的特点和用法,在这一篇主要讲解一下GCD的用法。 GCD(Grand ...

网友评论

      本文标题:GCD(用法二)

      本文链接:https://www.haomeiwen.com/subject/bmglqqtx.html