主要涉及到的概念
- 任务:放在block中的代码,执行方式有 同步执行(sync) 和 异步执行(async)
- 队列: 串行队列(serial) 和 并发队列(concurrent)
- 主队列:本质是一个串行队列
- 全局队列:本质是一个并发队列
知识点:
- 主队列的任务一定在主线程执行,主线程可以执行非主队列的任务
- 同步执行不开辟子线程,在当前线程执行
- 异步执行具有开辟子线程的能力,但是不一定会开辟,后面会有例子
- 同步执行串行队列按照顺序串行执行
- 同步执行并发队列依然是按照顺序串行执行
- 异步执行串行队列会开辟一个子线程,按顺序执行队列任务
- 异步执行并发队列具备开辟多个子线程的能力
任务的执行方式有两种,队列有四种,共有8种组合,分别为:
同步执行+串行队列
dispatch_queue_t queueSerial = dispatch_queue_create("com.serial", DISPATCH_QUEUE_SERIAL);
void(^task)(void) = ^{
NSLog(@"task--%@",[NSThread currentThread]);
};
void(^task1)(void) = ^{
NSLog(@"task1--%@",[NSThread currentThread]);
};
dispatch_sync(queueSerial, task);
dispatch_sync(queueSerial, task1);
NSLog(@"end");
当前是在主线程运行,同步执行会阻塞当前线程(主线程),所以end会在执行完task和task1之后输出,
dispatch_sync(queueSerial, task);
- 同步执行
dispatch_sync阻塞当前线程(主线程) - 向串行队列
queueSerial中插入任务task - 在当前线程(主线程)执行
task任务 task任务执行完成解除对当前线程(主线程)的阻塞
dispatch_sync(queueSerial, task1); //同理
- 同步执行
dispatch_sync阻塞当前线程(主线程) - 向串行队列
queueSerial中插入任务task1 - 在当前线程(主线程)执行
task1任务 task1任务执行完成解除对当前线程(主线程)的阻塞
所以执行顺序为task->task1->end
同步执行+并发队列
dispatch_queue_t queueConcurrent = dispatch_queue_create("com.conc", DISPATCH_QUEUE_CONCURRENT);
void(^task)(void) = ^{
NSLog(@"task--%@",[NSThread currentThread]);
};
void(^task1)(void) = ^{
NSLog(@"task1--%@",[NSThread currentThread]);
};
dispatch_sync(queueConcurrent, task);
dispatch_sync(queueConcurrent, task1);
NSLog(@"end");
在当前线程同步执行无论是串行队列还是并发队列任务都是按照顺序执行,其结果和 同步执行+串行队列 一致
同步执行全局队列
//第一个参数是队列优先级,第二个参数是保留值默认传0
dispatch_queue_t queueGlobal = dispatch_get_global_queue(0, 0);
void(^task)(void) = ^{
NSLog(@"task--%@",[NSThread currentThread]);
};
void(^task1)(void) = ^{
NSLog(@"task1--%@",[NSThread currentThread]);
};
dispatch_sync(queueGlobal, task);
dispatch_sync(queueGlobal, task1);
NSLog(@"end");
全局队列本质是并发队列,其结果和 同步执行+并发队列 一致
同步执行主队列
dispatch_queue_t queueMain = dispatch_get_main_queue();
void(^task)(void) = ^{
NSLog(@"task--%@",[NSThread currentThread]);
};
void(^task1)(void) = ^{
NSLog(@"task1--%@",[NSThread currentThread]);
};
dispatch_sync(queueMain, task); //我也是一个任务 记为 sync1
dispatch_sync(queueMain, task1);
NSLog(@"end");
这种情况比较特殊,会引起死锁,其原因是同步执行语句dispatch_sync(queueMain, task);本身也是一个任务,我们记为 sync1,sync1任务是在当前线程(主线程)同步执行的,sync1任务是向主队列中添加一个任务task并在当前线程(主线程)同步执行任务task,也就是说sync1任务执行完成的前提是task任务执行完成。
因为task任务是在sync1任务之后插入主队列的,所以主线程要先执行完sync1任务才会去执行task任务,而sync1任务执行完成的前提是task任务执行完成,所以就陷入了死锁状态,造成崩溃。
类似的
dispatch_queue_t queueSerial = dispatch_queue_create("com.serial", DISPATCH_QUEUE_SERIAL);
void(^task1)(void) = ^{
NSLog(@"死锁了吗");
};
void(^task2)(void) = ^{
dispatch_sync(queueSerial, task1);
};
//开辟子线程,并向串行队列queueSerial中添加任务 task2
dispatch_async(queueSerial, task2);
dispatch_async(queueSerial, task2);本身也是一个任务记为sync1,但不同的是sync1是在当前线程(主线程)执行,sync1任务执行结果是向串行队列queueSerial中添加任务task2并开辟子线程执行task2,任务task2是向串行队列queueSerial中添加任务task1并在当前线程同步执行任务task1,也就是说task2任务执行完成的前提是task1任务执行完成,因为task2任务比task1任务先添加到串行队列queueSerial,所以任务task2执行完成之后才会去执行tasi1,
注意:异步执行+串行队列只会开辟一条子线程
异步执行串行队列
dispatch_queue_t queueSerial = dispatch_queue_create("com.serial", DISPATCH_QUEUE_SERIAL);
void(^task)(void) = ^{
NSLog(@"task--%@",[NSThread currentThread]);
};
void(^task1)(void) = ^{
NSLog(@"task1--%@",[NSThread currentThread]);
};
dispatch_async(queueSerial, task); //我也是一个任务 记为 sync1
dispatch_async(queueSerial, task1);
NSLog(@"end");
将task和task1分别添加到串行队列queueSerial,开辟一条子线程顺序执行队列queueSerial中的任务,因为end是在主线程输出的,所以输出顺序为end->task->task1,因为异步执行+串行队列只开辟一条子线程,所以task和task1在同一个线程中执行
异步执行并发队列
这个时候理论上可以开辟多个子线程了
dispatch_queue_t queueConcurrent = dispatch_queue_create("com.conc", DISPATCH_QUEUE_CONCURRENT);
void(^task)(void) = ^{
NSLog(@"task--%@",[NSThread currentThread]);
};
void(^task1)(void) = ^{
NSLog(@"task1--%@",[NSThread currentThread]);
};
dispatch_async(queueConcurrent, task);
dispatch_async(queueConcurrent, task1);
NSLog(@"end");
因为task和task1有可能不是在同一个字线程执行的,两个任务不一定谁先结束执行,所以不能确定task和task1谁先输出,因为end是在主线程输出的,所以先输出end
异步执行主队列
dispatch_queue_t queueMain = dispatch_get_main_queue();
void(^task)(void) = ^{
NSLog(@"task--%@",[NSThread currentThread]);
};
void(^task1)(void) = ^{
NSLog(@"task1--%@",[NSThread currentThread]);
};
dispatch_async(queueMain, task);
dispatch_async(queueMain, task1);
主队列本质上也是一个串行队列,所以按照顺序执行task->task1,另外祝队列任务只能在主线程执行,所以task和task1都在主线程执行
异步执行全局队列
dispatch_queue_t queueGlobal = dispatch_get_global_queue(0, 0);
void(^task)(void) = ^{
NSLog(@"task--%@",[NSThread currentThread]);
};
void(^task1)(void) = ^{
NSLog(@"task1--%@",[NSThread currentThread]);
};
dispatch_async(queueGlobal, task);
dispatch_async(queueGlobal, task1);
全局队列是一个并发队列,所以有能力开辟多个子线程,当然也可能在一个子线程中去执行
线程间通讯
我们需要将一些耗时任务放在子线程,执行完毕之后再回到主线程刷新页面
dispatch_queue_t queueMain = dispatch_get_main_queue();
dispatch_queue_t queueGlobal = dispatch_get_global_queue(0, 0);
dispatch_async(queueGlobal, ^{
sleep(3);//模拟耗时操作
dispatch_async(queueMain, ^{
NSLog(@"主线程");
});
});
GCD 栅栏方法:dispatch_barrier_async
在《程序员的自我修养:链接、装载与库。》一书的过度优化部分有这么一段话
“CPU的乱序执行能力让我们对多线程的安全保障的努力变得异常困难。因此要保证线程安全,阻止CPU换序是必需的。遗憾的是,现在并不存在可移植的阻止换序的方法。通常情况下是调用CPU提供的一条指令,这条指令常常被称为barrier。一条barrier指令会阻止CPU将该指令之前的指令交换到barrier之后,反之亦然。换句话说,barrier指令的作用类似于一个拦水坝,阻止换序“穿透”这个大坝。”
摘录来自: 俞甲子 石凡 潘爱民. “程序员的自我修养:链接、装载与库。” Apple Books.
为了保证某些操作的原子性,CUP提供了barrier指令,用来保证在barrier指令之前的指令执行完成之后才会执行barrier之后的指令,dispatch_barrier_async的意思大体也是如此,在异步执行并发队列中保证先执行完dispatch_barrier_async之前的任务,然后再执行dispatch_barrier_async中的任务,其次执行dispatch_barrier_async之后的任务
dispatch_queue_t queueGlobal = dispatch_get_global_queue(0, 0);
dispatch_async(queueGlobal, ^{
NSLog(@"1--%@",[NSThread currentThread]);
});
dispatch_async(queueGlobal, ^{
sleep(2);
NSLog(@"2--%@",[NSThread currentThread]);
});
dispatch_barrier_async(queueGlobal, ^{
NSLog(@"barrier--%@",[NSThread currentThread]);
});
dispatch_async(queueGlobal, ^{
NSLog(@"3--%@",[NSThread currentThread]);
});
dispatch_async(queueGlobal, ^{
NSLog(@"4--%@",[NSThread currentThread]);
});
全局队列是一个并发队列,盲猜这里应该先打印出来1和2,然后执行barrier,然后随机打出3和4,但是实际上呢
barrier似乎跟dispatch_async一样,并没有起到什么作用,查了一番资料终于在官方文档找到正解
dispatch_barrier_async
如果自己通过dispatch_queue_create创建并发队列没问题,如果是一个串行队列或者全局并发队列那么和dispatch_async效果一样一样的,我们换成自己创建的并发队列
dispatch_queue_t queueConcurrent = dispatch_queue_create("com.conc", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queueConcurrent, ^{
NSLog(@"1--%@",[NSThread currentThread]);
});
dispatch_async(queueConcurrent, ^{
sleep(2);
NSLog(@"2--%@",[NSThread currentThread]);
});
dispatch_barrier_async(queueConcurrent, ^{
NSLog(@"barrier--%@",[NSThread currentThread]);
});
dispatch_async(queueConcurrent, ^{
NSLog(@"3--%@",[NSThread currentThread]);
});
dispatch_async(queueConcurrent, ^{
NSLog(@"4--%@",[NSThread currentThread]);
});
NSLog(@"end");
从结果看到dispatch_barrier_async并没有阻塞当前线程,而只是阻塞了当前异步队列其他任务的执行,官方文档也证实了这一点
dispatch_barrier_sync
我们先去官方文档看一下dispatch_barrier_sync
一方面dispatch_barrier_sync会阻塞当前线程,另一方面可能造成死锁deadlock,我们验证一下
dispatch_queue_t queueConcurrent = dispatch_queue_create("com.conc", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queueConcurrent, ^{
sleep(2);
NSLog(@"1--%@",[NSThread currentThread]);
});
dispatch_async(queueConcurrent, ^{
NSLog(@"2--%@",[NSThread currentThread]);
});
dispatch_barrier_sync(queueConcurrent, ^{
NSLog(@"barrier--%@",[NSThread currentThread]);
});
dispatch_async(queueConcurrent, ^{
NSLog(@"3--%@",[NSThread currentThread]);
});
dispatch_async(queueConcurrent, ^{
NSLog(@"4--%@",[NSThread currentThread]);
});
NSLog(@"end");
我们看到dispatch_barrier_sync确实阻塞了当前线程,end是在dispatch_barrier_sync之后输出的
dispatch_queue_t queueConcurrent = dispatch_queue_create("com.conc", DISPATCH_QUEUE_CONCURRENT);
dispatch_barrier_sync(queueConcurrent, ^{
NSLog(@"barrier--%@",[NSThread currentThread]);
dispatch_sync(queueConcurrent, ^{
NSLog(@"%@",[NSThread currentThread]);
});
});
不知道这是不是文档中所说的Calling this function and targeting the current queue results in deadlock.反正实现了deadlock效果
另外文档提到了Block_copy
我从源码看到确实dispatch_barrier_async调用了_dispatch_Block_copy
而dispatch_barrier_sync是没有copy,这可能是因为dispatch_barrier_sync阻塞线程后面代码不执行,而dispatch_barrier_async没有阻塞线程,那么后面就可能对函数体修改????所以拷贝一份这里留下问好
GCD 延时执行方法:dispatch_after
2秒之后将任务添加到主队列,具体什么时候执行还要看CUP的调度
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0*NSEC_PER_SEC)), mainQueue, ^{
//2秒之后将任务添加到主队列,具体什么时候执行还要看CUP的调度
NSLog(@"执行了");
});
GCD 一次性代码(只执行一次):dispatch_once
实现单例
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//单例
});
更多内容可以看一下# iOS多线程之dispatch_once剖析
GCD 快速迭代方法:dispatch_apply
先来看一下文档dispatch_apply
可以看到dispatch_apply和可重入且安全的并发队列可以实现高效的遍历操作,如果是一个串行队列那么就体现不出来他的高效之处了
dispatch_apply(10, queueGlobal, ^(size_t index) {
NSLog(@"%zd--%@",index,[NSThread currentThread]);
});
NSLog(@"end");
dispatch_apply会利用多个线程来遍历,不光是子线程,还可以调用主线程,另外他还会阻塞当前线程
Dispatch Group
dispatch_group作为一个单元监控一组任务。你可以将一组任务放到一个组里通过dispatch_group同步他们的行为。你可以将这些任务放在组里以后在同一个队列或者不同的队列异步执行,可以在不阻塞当前线程的情况下监听这些异步任务执行完毕,也可以阻塞当前线程等待这些任务完成。
dispatch_group_notify
dispatch_queue_t queueGlobal = dispatch_get_global_queue(0, 0);
dispatch_group_async(group, queueGlobal, ^{
sleep(2);
NSLog(@"1--%@",[NSThread currentThread]);
});
dispatch_group_async(group, queueGlobal, ^{
NSLog(@"2--%@",[NSThread currentThread]);
});
dispatch_group_async(group, queueGlobal, ^{
sleep(1);
NSLog(@"3--%@",[NSThread currentThread]);
});
dispatch_group_notify(group, queueGlobal, ^{
NSLog(@"notify--%@",[NSThread currentThread]);
});
NSLog(@"end--%@",[NSThread currentThread]);
dispatch_group_notify并没有阻塞当前线程,他是在当前组的其他队列都执行完成之后再执行,我们可以将dispatch_group_notify任务放在主队列执行,这就实现了回调主线程的功能
dispatch_queue_t queueSerial = dispatch_queue_create("com.serial", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queueMain = dispatch_get_main_queue();
dispatch_queue_t queueGlobal = dispatch_get_global_queue(0, 0);
dispatch_group_async(group, queueGlobal, ^{
sleep(2);
NSLog(@"1--%@",[NSThread currentThread]);
});
dispatch_group_async(group, queueSerial, ^{
sleep(1);
NSLog(@"2--%@",[NSThread currentThread]);
});
dispatch_group_async(group, queueSerial, ^{
NSLog(@"3--%@",[NSThread currentThread]);
});
dispatch_group_notify(group, queueMain, ^{
NSLog(@"notify--%@",[NSThread currentThread]);
});
NSLog(@"end--%@",[NSThread currentThread]);
dispatch_group_wait
阻塞当前线程,等待组内任务都执行完成才会继续执行
dispatch_queue_t queueGlobal = dispatch_get_global_queue(0, 0);
dispatch_group_async(group, queueGlobal, ^{
sleep(2);
NSLog(@"1--%@",[NSThread currentThread]);
});
dispatch_group_async(group, queueGlobal, ^{
sleep(1);
NSLog(@"2--%@",[NSThread currentThread]);
});
dispatch_group_async(group, queueGlobal, ^{
NSLog(@"3--%@",[NSThread currentThread]);
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"end--%@",[NSThread currentThread]);
直到前面三个任务都执行完成才会打印end,当然也可以将阻塞的超时时间设置小一些,即使前面任务没有完成,但是时间到了也会继续执行
dispatch_queue_t queueGlobal = dispatch_get_global_queue(0, 0);
dispatch_group_async(group, queueGlobal, ^{
sleep(3);
NSLog(@"1--%@",[NSThread currentThread]);
});
dispatch_group_async(group, queueGlobal, ^{
sleep(1);
NSLog(@"2--%@",[NSThread currentThread]);
});
dispatch_group_async(group, queueGlobal, ^{
NSLog(@"3--%@",[NSThread currentThread]);
});
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2*NSEC_PER_SEC)));
NSLog(@"end--%@",[NSThread currentThread]);
dispatch_group_enter、dispatch_group_leave
dispatch_group_async内部也是通过dispatch_group_enter和dispatch_group_leave来实现的
dispatch_queue_t queueGlobal = dispatch_get_global_queue(0, 0);
dispatch_group_enter(group);
dispatch_async(queueGlobal, ^{
sleep(3);
NSLog(@"1--%@",[NSThread currentThread]);
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queueGlobal, ^{
sleep(1);
NSLog(@"2--%@",[NSThread currentThread]);
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queueGlobal, ^{
NSLog(@"3--%@",[NSThread currentThread]);
dispatch_group_leave(group);
});
dispatch_group_notify(group, queueGlobal, ^{
NSLog(@"notify--%@",[NSThread currentThread]);
});
NSLog(@"end--%@",[NSThread currentThread]);
实现了和dispatch_group_async一样的效果
信号量semaphore
在开发中经常需要线程同步,那么信号量是一个很好的选择,dispatch_semaphore_signal信号量+1,dispatch_semaphore_wait信号量-1,如果信号量小于0那么阻塞当前线程,可以设置阻塞的超时时间
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_async(queueGlobal, ^{
sleep(3);//耗时操作
NSLog(@"1--%@",[NSThread currentThread]);
dispatch_semaphore_signal(semaphore);//信号量+1
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//信号量-1
dispatch_async(queueMain, ^{
NSLog(@"主线程");
});
NSLog(@"end--%@",[NSThread currentThread]);
多线程访问同一个数据有可能造成数据不安全,例如
__block int i = 5;
while (i>0) {
dispatch_async(queueGlobal, ^{
i--;
NSLog(@"%d--%@",i,[NSThread currentThread]);
});
}
由于多线程同时修改i导致结果和预期出现了很大的出入,甚至NSLog函数的打印都出问题了😂,通过信号量可以解决这个问题
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block int i = 5;
while (i>0) {
dispatch_async(queueGlobal, ^{
i--;
NSLog(@"%d--%@",i,[NSThread currentThread]);
dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}
这个时候我们看到结果按照预期输出了,因为信号量控制最多只有一个线程可以访问变量i(不一定是同一个线程,但同一时间最多只能有一个线程访问)
dispatch_set_target_queue
dispatch_set_target_queue有两个作用一是改变队列优先级,二是让多个串行队列之间也能串行地执行任务。
我们前边所学的方法都是控制队列内部的任务的操作顺序,但是不同队列之间是没有依赖关系的,假如我们把A任务放在自定义串行队列serialQueueA中,把B任务放在自定义并发队列conQueueB中,那么我们不知道任务A和任务B的先后执行顺序,有了dispatch_set_target_queue我们可以利用其改变队列优先级的作用实现优先队列
改变队列优先级实现优先队列
dispatch_queue_create 创建的队列,无论是串行还是并发,其优先级都是 DISPATCH_QUEUE_PRIORITY_DEFAULT,使用 dispatch_set_target_queue 可以改变队列优先级,注意改变的是优先调度开始顺序,而不是结束顺序,先被调度的不一定先结束执行
dispatch_queue_t serialQueue1 = dispatch_queue_create("serialQueue1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue2 = dispatch_queue_create("serialQueue2", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue3 = dispatch_queue_create("serialQueue3", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue4 = dispatch_queue_create("serialQueue4", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue5 = dispatch_queue_create("serialQueue5", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue6 = dispatch_queue_create("serialQueue6", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue7 = dispatch_queue_create("serialQueue7", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue8 = dispatch_queue_create("serialQueue8", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue1, ^{
NSLog(@"taskA");
});
dispatch_async(serialQueue2, ^{
NSLog(@"taskB");
});
dispatch_async(serialQueue3, ^{
NSLog(@"taskC");
});
dispatch_async(serialQueue4, ^{
NSLog(@"taskD");
});
dispatch_async(serialQueue5, ^{
NSLog(@"taskE");
});
dispatch_async(serialQueue6, ^{
NSLog(@"taskF");
});
dispatch_async(serialQueue7, ^{
NSLog(@"taskG");
});
dispatch_async(serialQueue8, ^{
NSLog(@"taskH");
});
这个时候我们不能确定ABCDEFGH谁先执行,简单修改一下
dispatch_queue_t serialQueue1 = dispatch_queue_create("serialQueue1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue2 = dispatch_queue_create("serialQueue2", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue3 = dispatch_queue_create("serialQueue3", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue4 = dispatch_queue_create("serialQueue4", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue5 = dispatch_queue_create("serialQueue5", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue6 = dispatch_queue_create("serialQueue6", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue7 = dispatch_queue_create("serialQueue7", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue8 = dispatch_queue_create("serialQueue8", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t globalQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_set_target_queue(serialQueue2, globalQueueLow);
dispatch_async(serialQueue1, ^{
NSLog(@"taskA");
});
dispatch_async(serialQueue2, ^{
NSLog(@"taskB");
});
dispatch_async(serialQueue3, ^{
NSLog(@"taskC");
});
dispatch_async(serialQueue4, ^{
NSLog(@"taskD");
});
dispatch_async(serialQueue5, ^{
NSLog(@"taskE");
});
dispatch_async(serialQueue6, ^{
NSLog(@"taskF");
});
dispatch_async(serialQueue7, ^{
NSLog(@"taskG");
});
dispatch_async(serialQueue8, ^{
NSLog(@"taskH");
});
我们增加了两行代码
dispatch_queue_t globalQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_set_target_queue(serialQueue2, globalQueueLow);
网上看了好多例子都是到此为止,以至于我任务只是因为我给globalQueueLow设置的优先级为DISPATCH_QUEUE_PRIORITY_BACKGROUND所以serialQueue2的优先级才笔另外几个串行队列低,如果我设置优先级为DISPATCH_QUEUE_PRIORITY_HIGH那么队列就会优先调度
dispatch_queue_t serialQueue1 = dispatch_queue_create("serialQueue1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue2 = dispatch_queue_create("serialQueue2", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue3 = dispatch_queue_create("serialQueue3", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue4 = dispatch_queue_create("serialQueue4", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue5 = dispatch_queue_create("serialQueue5", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue6 = dispatch_queue_create("serialQueue6", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue7 = dispatch_queue_create("serialQueue7", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue8 = dispatch_queue_create("serialQueue8", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t globalQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_queue_t globalQueueHight = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_set_target_queue(serialQueue2, globalQueueLow);
dispatch_set_target_queue(serialQueue3, globalQueueHight);
dispatch_async(serialQueue1, ^{
NSLog(@"taskA");
});
dispatch_async(serialQueue2, ^{
NSLog(@"taskB");
});
dispatch_async(serialQueue3, ^{
NSLog(@"taskC");
});
dispatch_async(serialQueue4, ^{
NSLog(@"taskD");
});
dispatch_async(serialQueue5, ^{
NSLog(@"taskE");
});
dispatch_async(serialQueue6, ^{
NSLog(@"taskF");
});
dispatch_async(serialQueue7, ^{
NSLog(@"taskG");
});
dispatch_async(serialQueue8, ^{
NSLog(@"taskH");
});
多运行几次我们发现设置DISPATCH_QUEUE_PRIORITY_HIGH优先级之后串行队列serialQueue3并没有比其他优先级高,而仅仅比serialQueue2高了而已,我们前边也说过,这种优先级高仅仅是开始调度的优先级高,而不是结束调度的优先级,如果我们给任务A设置一个耗时任务就可以验证
dispatch_async(serialQueue1, ^{
int a=0;
for (int i=0; i<1000000; i++) {
a++;
}
NSLog(@"%d-taskA",a);
});
这时A并没有先结束执行,BC也没有最后结束执行
如果我们设置
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_set_target_queue(serialQueue3, mainQueue);
这个时候是不是serialQueue3的优先级会不会很高呢,其实并没有
看了官方文档也是很难理解dispatch_set_target_queue,我个人理解是如果通过dispatch_set_target_queue设置队列优先级的这些队列他们都成了二级公民,依赖于同一个队列的子队列之间可以通过优先级来设置,但是他们的优先级都要比没有设置过优先级的队列优先级要低了
我们可以使用dispatch_set_target_queue+dispatch_suspend/dispatch_resume实现一个优先队列
dispatch_queue_t serialQueue1 = dispatch_queue_create("serialQueue1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t serialQueue2 = dispatch_queue_create("serialQueue2", DISPATCH_QUEUE_SERIAL);
dispatch_set_target_queue(serialQueue1, serialQueue2);
dispatch_async(serialQueue1, ^{
NSLog(@"taskA");
});
dispatch_suspend(serialQueue1);
dispatch_async(serialQueue2, ^{
NSLog(@"taskB");
dispatch_resume(serialQueue1);
});
dispatch_async(serialQueue1, ^{
NSLog(@"taskC");
});