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] {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==={number = 10, name = (null)}

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

2018-11-23 10:17:33.576227+0800 OC-Swift[1732:40796] 111==={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==={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] {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==={number = 3, name = (null)}

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

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

2018-11-23 10:54:37.383249+0800 OC-Swift[2129:58027] 333==={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] {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==={number = 5, name = (null)}

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

2018-11-23 10:57:57.257480+0800 OC-Swift[2168:59658] 222==={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==={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] {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==={number = 3, name = (null)}

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

2018-11-23 10:21:15.962720+0800 OC-Swift[1821:43870] 111==={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] {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==={number = 3, name = (null)}

2018-11-23 11:12:07.777851+0800 OC-Swift[2329:66032] 111==={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==={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] {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==={number = 5, name = (null)}

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

2018-11-23 14:34:25.790326+0800 OC-Swift[4127:148486] 333==={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==={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==={number = 3, name = (null)}

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

2018-11-23 15:59:09.550970+0800 OC-Swift[5031:183298] 222==={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==={number = 3, name = (null)}

结果分析:

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

你可能感兴趣的:(GCD(用法二))