iOS-GCD系列之dispatch_group_t

这篇主要将对dispatch_group_t进行梳理应用,其主要用于监听管理任务组中任务完成情况,在任务完成后做一些操作处理。

最常见的几个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 创建一个任务组
dispatch_group_create();
// 将任务异步提交到任务组里
dispatch_group_async(group, queue, block);
// 不使用dispatch_group_async来提交任务
// 任务组中任务数+1
dispatch_group_enter(group);
// 任务组中任务数-1与dispatch_group_enter必须成对出现
dispatch_group_leave(group);
// 等待之前任务执行完成后才继续执行
dispatch_group_wait(group1, DISPATCH_TIME_FOREVER);
// 当任务组中任务完成,会出发出发此方法的block
dispatch_group_notify(group1, queue1,block);

实战

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 创建任务组
dispatch_group_t group = dispatch_group_create();
// 创建串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("com.wynter.serial", DISPATCH_QUEUE_SERIAL);
// 创建并发队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.wynter.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_async(group, concurrentQueue, ^{
sleep(3);
NSLog(@"并发队列任务1,当前线程:%@", [NSThread currentThread]);
});
dispatch_group_async(group, serialQueue, ^{
sleep(2);
NSLog(@"串行队列任务1,当前线程:%@", [NSThread currentThread]);
});
dispatch_group_async(group, serialQueue, ^{
sleep(2);
NSLog(@"串行队列任务2,当前线程:%@", [NSThread currentThread]);
});
// 在任务组中并发执行,等同与dispatch_group_async(group, concurrentQueue, block)
dispatch_group_enter(group);
dispatch_async(concurrentQueue, ^{
sleep(2);
NSLog(@"并发队列任务2(enter/leave),当前线程:%@", [NSThread currentThread]);
dispatch_group_leave(group);
});
// 开始等待阻塞全部线程,直到任务中之前任务执行完成
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"结束任务组中已执行任务的等待,继续向下执行任务");
dispatch_group_async(group, concurrentQueue, ^{
sleep(1);
NSLog(@"并发队列任务3,当前线程:%@", [NSThread currentThread]);
});
// 同一线程中通知任务组中队列中任务已经完成,故顺序打印通知结果
dispatch_group_notify(group, concurrentQueue, ^{
NSLog(@"并发队列任务执行完毕,当前线程:%@", [NSThread currentThread]);
});
dispatch_group_notify(group, serialQueue, ^{
NSLog(@"串行队列任务执行完毕,当前线程:%@", [NSThread currentThread]);
});
/*
2017-12-15 11:11:46.761678+0800 GCD[32253:17053663] 并发队列任务2(enter/leave),当前线程<NSThread: 0x60400026d0c0>{number = 4, name = (null)}
2017-12-15 11:11:46.761678+0800 GCD[32253:17053661] 串行队列任务1,当前线程:<NSThread: 0x60000026c280>{number = 3, name = (null)}
2017-12-15 11:11:47.761193+0800 GCD[32253:17053660] 并发队列任务1,当前线程:<NSThread: 0x60000026c540>{number = 5, name = (null)}
2017-12-15 11:11:48.762938+0800 GCD[32253:17053661] 串行队列任务2,当前线程:<NSThread: 0x60000026c280>{number = 3, name = (null)}
2017-12-15 11:11:48.762940+0800 GCD[32356:17074006] 结束任务组中已执行任务的等待,继续向下执行任务
2017-12-15 11:11:49.767551+0800 GCD[32253:17053661] 并发队列任务3,当前线程:<NSThread: 0x60000026c280>{number = 3, name = (null)}
2017-12-15 11:11:49.768026+0800 GCD[33057:17230402] 并发队列任务执行完毕,当前线程:<NSThread: 0x60000026c480>{number = 3, name = (null)}
2017-12-15 11:11:49.768248+0800 GCD[33057:17230226] 串行队列任务执行完毕,当前线程:<NSThread: 0x60400027e300>{number = 5, name = (null)}
*/

1、创建串行、并发队列各一个
2、向任务组的并发队列中添加了 3秒后执行并发队列任务1、2秒后并发队列任务2(enter/leave)、1秒后执行任务3
3、向任务组的串行队列中添加了 2秒后执行串行队列任务1、2秒后执行串行队列任务2
4、在并发队列任务2(enter/leave)后添加了任务等待
5、通知任务完成

2个并发队列任务开辟两条新线程,并发执行耗时3秒,同时串行队列中的2个任务在同一线程中执行耗时4秒。因为在并发任务后添加任务组等待方法,所以并发队列任务3要等前面4个任务执行完毕才能执行,任务组总共耗时5秒,如果去掉任务等待耗时为4秒。

总结

  • 使用dispatch_sync/dispatch_async来处理同步或异步,其实完没有必要,串行并发队列完全可以满足需求,并且使用dispatch_async会导致任务组提前通知完成;
  • 任务组通知不区分串还是并行队列,任务组中所有任务执行完成才会收到通知。