GCD
1、GCD全称 Grand Central Dispatch ,是纯C语言,提供了非常多强大的函数,来进行系统线程的管理。
2、优势:GCD是苹果公司为多核的并行运算提出的解决方案。GCD会自动利用更多的CPU内核,会自动管理线程的生命周期(创建线程、调度任务、销毁线程),程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码。
并发 | 串行 | 主队列 | |
---|---|---|---|
同步(sync) | 没有开启新线程 串行执行任务 | 没有开启新线程 串行执行 | 锁死 |
异步(async) | 有开启新线程 并行执行 | 有开启新线程 串行执行 | 没开启新线程 串行执行 |
串行 (DISPATCH_QUEUE_SERIAL)
并发 (DISPATCH_QUEUE_CONCURRENT)
四种组合方式
同步执行 + 并发队列
/**
同步 + 并发
在当前线程中执行任务,不会开启新线程,执行完一个任务,再执行下一个任务。
*/
- (void)synchronousAndConcurrent{
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程
NSLog(@"synchronousAndConcurrent---begin"); //线程开始
dispatch_queue_t queue = dispatch_queue_create("com.leocy.gcd", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
// 添加任务1
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_sync(queue, ^{
// 添加任务2
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_sync(queue, ^{
// 添加任务3
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程
}
});
NSLog(@"synchronousAndConcurrent---end"); //线程结束
}
运行结果:没开启新线程,串行执行
2019-01-15 17:31:46.958190+0800 GCD使用[11901:3502931] currentThread—<NSThread: 0x283c32e00>{number = 1, name = main}
2019-01-15 17:31:46.958258+0800 GCD使用[11901:3502931] synchronousAndConcurrent—begin
2019-01-15 17:31:48.959827+0800 GCD使用[11901:3502931] 1—<NSThread: 0x283c32e00>{number = 1, name = main}
2019-01-15 17:31:50.961196+0800 GCD使用[11901:3502931] 1—<NSThread: 0x283c32e00>{number = 1, name = main}
2019-01-15 17:31:52.962809+0800 GCD使用[11901:3502931] 2—<NSThread: 0x283c32e00>{number = 1, name = main}
2019-01-15 17:31:54.963861+0800 GCD使用[11901:3502931] 2—<NSThread: 0x283c32e00>{number = 1, name = main}
2019-01-15 17:31:56.965229+0800 GCD使用[11901:3502931] 3—<NSThread: 0x283c32e00>{number = 1, name = main}
2019-01-15 17:31:58.966589+0800 GCD使用[11901:3502931] 3—<NSThread: 0x283c32e00>{number = 1, name = main}
2019-01-15 17:32:02.847758+0800 GCD使用[11901:3502931] synchronousAndConcurrent—end
(lldb)
异步执行 + 并发队列
/**
异步 + 并发
可以开启多个线程,任务交替(同时)执行。
*/
- (void)asynchronousAndConcurrent{
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程
NSLog(@"synchronousAndSerial---begin"); //线程开始
dispatch_queue_t queue = dispatch_queue_create("com.leocy.gcd", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
// 添加任务1
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_async(queue, ^{
// 添加任务2
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_async(queue, ^{
// 添加任务3
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程
}
});
NSLog(@"asynchronousAndConcurrent---end"); //线程结束
}
执行结果:开启新线程,并发执行
2019-01-15 17:34:40.553187+0800 GCD使用[11912:3504396] currentThread—<NSThread: 0x281dbee40>{number = 1, name = main}
2019-01-15 17:34:40.553228+0800 GCD使用[11912:3504396] synchronousAndSerial—begin
2019-01-15 17:34:40.553262+0800 GCD使用[11912:3504396] asynchronousAndConcurrent—end
2019-01-15 17:34:44.382094+0800 GCD使用[11912:3504445] 3—<NSThread: 0x281df02c0>{number = 5, name = (null)}
2019-01-15 17:34:44.382096+0800 GCD使用[11912:3504446] 1—<NSThread: 0x281dd4540>{number = 4, name = (null)}
2019-01-15 17:34:44.382237+0800 GCD使用[11912:3504443] 2—<NSThread: 0x281de2100>{number = 3, name = (null)}
2019-01-15 17:34:46.385780+0800 GCD使用[11912:3504443] 2—<NSThread: 0x281de2100>{number = 3, name = (null)}
2019-01-15 17:34:46.385779+0800 GCD使用[11912:3504445] 3—<NSThread: 0x281df02c0>{number = 5, name = (null)}
2019-01-15 17:34:46.385779+0800 GCD使用[11912:3504446] 1—<NSThread: 0x281dd4540>{number = 4, name = (null)}
同步执行 + 串行队列
/**
同步 + 串行
不会开启新线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个任务。
*/
- (void)synchronousAndSerial{
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程
NSLog(@"synchronousAndSerial---begin"); //线程开始
dispatch_queue_t queue = dispatch_queue_create("com.leocy.gcd", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
// 添加任务1
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_sync(queue, ^{
// 添加任务2
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_sync(queue, ^{
// 添加任务3
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程
}
});
NSLog(@"synchronousAndSerial---end"); //线程结束
}
执行结果:没开启新线程,串行执行
2019-01-15 17:33:37.132737+0800 GCD使用[11907:3503870] currentThread—<NSThread: 0x2815e2e40>{number = 1, name = main}
2019-01-15 17:33:37.132774+0800 GCD使用[11907:3503870] synchronousAndSerial—begin
2019-01-15 17:33:39.134268+0800 GCD使用[11907:3503870] 1—<NSThread: 0x2815e2e40>{number = 1, name = main}
2019-01-15 17:33:41.135846+0800 GCD使用[11907:3503870] 1—<NSThread: 0x2815e2e40>{number = 1, name = main}
2019-01-15 17:33:43.137197+0800 GCD使用[11907:3503870] 2—<NSThread: 0x2815e2e40>{number = 1, name = main}
2019-01-15 17:33:45.138594+0800 GCD使用[11907:3503870] 2—<NSThread: 0x2815e2e40>{number = 1, name = main}
2019-01-15 17:33:47.140036+0800 GCD使用[11907:3503870] 3—<NSThread: 0x2815e2e40>{number = 1, name = main}
2019-01-15 17:33:49.141438+0800 GCD使用[11907:3503870] 3—<NSThread: 0x2815e2e40>{number = 1, name = main}
2019-01-15 17:33:49.141599+0800 GCD使用[11907:3503870] synchronousAndSerial—end
(lldb)
异步执行 + 串行队列
/**
异步 + 串行
特点:会开启一条新线程,但是因为任务是串行的,执行完一个任务,再执行下一个任务。
*/
- (void)asynchronousAndSerial{
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程
NSLog(@"synchronousAndSerial---begin"); //线程开始
dispatch_queue_t queue = dispatch_queue_create("com.leocy.gcd", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
// 添加任务1
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_async(queue, ^{
// 添加任务2
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_async(queue, ^{
// 添加任务3
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程
}
});
NSLog(@"synchronousAndSerial---end"); //线程结束
}
执行结果:开启一条新线程,串行执行
2019-01-15 17:35:35.597125+0800 GCD使用[11917:3504860] currentThread—<NSThread: 0x281265b80>{number = 1, name = main}
2019-01-15 17:35:35.597163+0800 GCD使用[11917:3504860] synchronousAndSerial—begin
2019-01-15 17:35:35.597196+0800 GCD使用[11917:3504860] synchronousAndSerial—end
2019-01-15 17:35:38.944090+0800 GCD使用[11917:3504894] 1—<NSThread: 0x281207740>{number = 4, name = (null)}
2019-01-15 17:35:40.949580+0800 GCD使用[11917:3504894] 1—<NSThread: 0x281207740>{number = 4, name = (null)}
2019-01-15 17:35:42.955068+0800 GCD使用[11917:3504894] 2—<NSThread: 0x281207740>{number = 4, name = (null)}
2019-01-15 17:35:44.960644+0800 GCD使用[11917:3504894] 2—<NSThread: 0x281207740>{number = 4, name = (null)}
2019-01-15 17:35:46.966089+0800 GCD使用[11917:3504894] 3—<NSThread: 0x281207740>{number = 4, name = (null)}
2019-01-15 17:35:48.971523+0800 GCD使用[11917:3504894] 3—<NSThread: 0x281207740>{number = 4, name = (null)}
特殊情况
同步执行 + 主队列
/**
* 同步 + 主队列
* 特点(主线程调用):互等卡主不执行。
* 特点(其他线程调用):不会开启新线程,执行完一个任务,再执行下一个任务。
*/
- (void) synchronousAndMain {
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程
NSLog(@"synchronousAndMain---begin");
dispatch_queue_t mainQueue = dispatch_get_main_queue();
// dispatch_queue_t mainQueue = dispatch_queue_create("com.leocy.gcd", DISPATCH_QUEUE_SERIAL);
dispatch_sync(mainQueue, ^{
// 追加任务1
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_sync(mainQueue, ^{
// 追加任务2
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_sync(mainQueue, ^{
// 追加任务3
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程
}
});
NSLog(@"synchronousAndMain---end");
}
执行结果:主线程调用:死锁卡住不执行 其他线程调用:没有开启新线程,串行执行任务
异步执行 + 主队列
/**
异步 + 主队列
*/
- (void)asynchrnousAndMain {
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程
NSLog(@"asynchrnousAndMain---begin");
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^{
// 追加任务1
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_async(mainQueue, ^{
// 追加任务2
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_async(mainQueue, ^{
// 追加任务3
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程
}
});
NSLog(@"asynchrnousAndMain---end");
}
执行结果:没开启新线程,串行执行
2019-01-15 17:39:53.716154+0800 GCD使用[11927:3506203] currentThread—<NSThread: 0x283c02e40>{number = 1, name = main}
2019-01-15 17:39:53.716196+0800 GCD使用[11927:3506203] asynchrnousAndMain—begin
2019-01-15 17:39:53.716226+0800 GCD使用[11927:3506203] asynchrnousAndMain—end
2019-01-15 17:39:57.868912+0800 GCD使用[11927:3506203] 1—<NSThread: 0x283c02e40>{number = 1, name = main}
2019-01-15 17:39:59.870304+0800 GCD使用[11927:3506203] 1—<NSThread: 0x283c02e40>{number = 1, name = main}
2019-01-15 17:40:01.871099+0800 GCD使用[11927:3506203] 2—<NSThread: 0x283c02e40>{number = 1, name = main}
2019-01-15 17:40:03.872303+0800 GCD使用[11927:3506203] 2—<NSThread: 0x283c02e40>{number = 1, name = main}
2019-01-15 17:40:05.873882+0800 GCD使用[11927:3506203] 3—<NSThread: 0x283c02e40>{number = 1, name = main}
2019-01-15 17:40:07.875393+0800 GCD使用[11927:3506203] 3—<NSThread: 0x283c02e40>{number = 1, name = main}
其他常用
栅栏 dispatch_barrier_async
dispatch_barrier_sync(queue, ^{
NSLog(@"========栅栏=========");
});
效果:栅栏上的上方的先执行,下方的待上方执行完毕后执行
延时 dispatch_after
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 5.0秒后异步追加任务代码到主队列,并开始执行
NSLog(@"after---%@",[NSThread currentThread]); // 打印当前线程
});
一次 dispatch_once (单例)
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
<#code to be executed once#>
});
对列组 dispatch_group
/**
* 队列组 dispatch_group_notify
*/
- (void)groupNotify {
NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程
NSLog(@"group---begin");
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 追加任务1
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"1---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 追加任务2
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"2---%@",[NSThread currentThread]); // 打印当前线程
}
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
for (int i = 0; i < 2; ++i) {
[NSThread sleepForTimeInterval:2]; // 模拟耗时操作
NSLog(@"3---%@",[NSThread currentThread]); // 打印当前线程
}
NSLog(@"group---end");
});
}
执行结果:等前面的异步任务1、任务2都执行完毕后,回到主线程执行下边任务
2019-01-15 18:09:51.686244+0800 GCD使用[11955:3516270] currentThread—<NSThread: 0x2831871c0>{number = 1, name = main}
2019-01-15 18:09:51.686295+0800 GCD使用[11955:3516270] group—begin
2019-01-15 18:09:55.980170+0800 GCD使用[11955:3516409] 2—<NSThread: 0x283186380>{number = 5, name = (null)}
2019-01-15 18:09:55.980168+0800 GCD使用[11955:3516410] 1—<NSThread: 0x2831a8380>{number = 4, name = (null)}
2019-01-15 18:09:57.985010+0800 GCD使用[11955:3516410] 1—<NSThread: 0x2831a8380>{number = 4, name = (null)}
2019-01-15 18:09:57.985670+0800 GCD使用[11955:3516409] 2—<NSThread: 0x283186380>{number = 5, name = (null)}
2019-01-15 18:09:59.987117+0800 GCD使用[11955:3516270] 3—<NSThread: 0x2831871c0>{number = 1, name = main}
2019-01-15 18:10:01.988533+0800 GCD使用[11955:3516270] 3—<NSThread: 0x2831871c0>{number = 1, name = main}
2019-01-15 18:10:01.988660+0800 GCD使用[11955:3516270] group—end