学计算机的那个

不是我觉到、悟到,你给不了我,给了也拿不住;只有我觉到、悟到,才有可能做到,能做到的才是我的.

0%

GCD队列优先级和队列组

GCD队列的服务质量与优先级

  • NSQualityOfServiceUserInteractive
    与用户交互的任务,这些任务通常跟 UI 级别的刷新相关,比如动画,这些任务需要在一瞬间完成;

  • NSQualityOfServiceUserInitiated
    由用户发起的并且需要立即得到结果的任务,比如滑动 scroll view 时去加载数据用于后续 cell 的显示,这些任务通常跟后续的用户交互相关,在几秒或者更短的时间内完成;

  • NSQualityOfServiceUtility
    一些可能需要花点时间的任务,这些任务不需要马上返回结果,比如下载的任务,这些任务可能花费几秒或者几分钟的时间;

  • NSQualityOfServiceBackground
    这些任务对用户不可见,比如后台进行备份的操作,这些任务可能需要较长的时间,几分钟甚至几个小时;

  • NSQualityOfServiceDefault
    优先级介于 user-initiatedutility,当没有 QoS 信息时默认使用,开发者不应该使用这个值来设置自己的任务。

服务质量枚举类型

1
2
3
4
5
QOS_CLASS_USER_INTERACTIVE
QOS_CLASS_USER_INITIATED
QOS_CLASS_DEFAULT
QOS_CLASS_UTILITY
QOS_CLASS_BACKGROUND

队列的优先级与服务质量的对应关系:

给队列设置QoS

dispatch_queue_attr_make_with_qos_class

dispatch_set_target_queue

GCD队列任务间依赖关系

dispatch_set_target_queue

除了能用来设置队列的 QoS 之外,还能够创建队列的层次体系。当我们想让不同队列中的任务同步的执行时,我们可以创建一个串行队列,然后将这些队列的 target 指向新创建的队列即可,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    dispatch_queue_t targetQueue = dispatch_queue_create("target_queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);
dispatch_set_target_queue(queue1, targetQueue);
dispatch_set_target_queue(queue2, targetQueue);
dispatch_async(queue1, ^{
NSLog(@"执行任务1,%s",dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
sleep(1);
});
dispatch_async(queue2, ^{
NSLog(@"执行任务2,%s",dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
sleep(1);
});
dispatch_async(queue2, ^{
NSLog(@"执行任务3,%s",dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
sleep(1);
});
/*
2020-02-01 19:05:18.142729+0800 多线程[6669:1213619] 执行任务1,queue1
2020-02-01 19:05:19.143926+0800 多线程[6669:1213619] 执行任务2,queue2
2020-02-01 19:05:20.147740+0800 多线程[6669:1213619] 执行任务3,queue2
*/

注意点: 避免相互依赖,如将队列 A 的目标队列设置为队列 B,并将队列 B 的目标队列设置为队列 A。

Dispatch Group队列组

GCD 队列组,又称“调度组”,实现所有任务执行完成后有一个统一的回调。

例如:异步下载歌曲,等所有歌曲都下载完毕以后,转到主线程提示用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_async(group, queue, ^{
NSLog(@"%@,下载歌曲1",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"%@,下载歌曲2",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"%@,下载歌曲3",[NSThread currentThread]);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"%@,下载完毕",[NSThread currentThread]);
});
/*
<NSThread: 0x6000028c8c00>{number = 6, name = (null)},下载歌曲2
<NSThread: 0x60000283f400>{number = 5, name = (null)},下载歌曲1
<NSThread: 0x600002803440>{number = 4, name = (null)},下载歌曲3
<NSThread: 0x60000285c5c0>{number = 1, name = main},下载完毕
*/

队列组的原理

真正实现统一回调的操作:

1
2
void dispatch_group_enter(dispatch_group_t group);
void dispatch_group_leave(dispatch_group_t group);
1
2
3
4
5
6
7
dispatch_group_async(group, queue, ^{ 
});
//等价于
dispatch_group_enter(group);
dispatch_async(queue, ^{
dispatch_group_leave(group);
});
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
    // 1.创建队列组
dispatch_group_t group = dispatch_group_create();
// 2.获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//ARC中不用写也不能写
// dispatch_retain(group);
// 3.进入队列组,执行此函数后,再添加的异步执行的block任务都会被group监听
dispatch_group_enter(group);
// 4.添加任务
dispatch_async(queue, ^{
NSLog(@"%@,执行任务1",[NSThread currentThread]);
// 5.离开队列组
dispatch_group_leave(group);
//ARC中不用写也不能写
// dispatch_release(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"%@,执行任务2",[NSThread currentThread]);
dispatch_group_leave(group);
});
// 6.获得队列组的通知
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"%@,执行任务3",[NSThread currentThread]);
});
// 7.等待队列组,监听的队列中的所有任务都执行完毕,才会执行后续代码,会阻塞线程(很少使用)
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"%@,执行任务4",[NSThread currentThread]);
/*
<NSThread: 0x600003d98d00>{number = 3, name = (null)},执行任务1
<NSThread: 0x600003d4de80>{number = 9, name = (null)},执行任务2
<NSThread: 0x600003dcd2c0>{number = 1, name = main},执行任务4
<NSThread: 0x600003dcd2c0>{number = 1, name = main},执行任务3
*/