We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
本文来自尚妆iOS团队嘉文 发表于尚妆github博客,欢迎订阅!
Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法 基于C语言,提供了非常多强大的函数
同步 (Synchronous) 在当前线程中执行任务,不具备开启新线程的能力 提交的任务在执行完成后才会返回 同步函数: dispatch_sync() 异步 (Asynchronous) 在新线程中执行任务,具备开启新线程的能力 提交的任务立刻返回,在后台队列中执行 异步函数: dispatch_async() 串行 (Serial) 一个任务执行完毕后,再执行下一个任务 并发 (Concurrent) 多个任务同时执行(自动开启多个线程),只有在异步函数下才有效
在当前线程中执行任务,不具备开启新线程的能力 提交的任务在执行完成后才会返回 同步函数: dispatch_sync()
在新线程中执行任务,具备开启新线程的能力 提交的任务立刻返回,在后台队列中执行 异步函数: dispatch_async()
一个任务执行完毕后,再执行下一个任务
多个任务同时执行(自动开启多个线程),只有在异步函数下才有效
只有在异步函数下才有效
1.所有的执行都放到队列中(queue),队列的特点是FIFO(先提交的先执行) 2.必须在主线程访问 UIKit 的类 3.并发队列只在异步函数下才有效
NSLog(@"当前线程: %@", [NSThread currentThread]); //获取主队列 dispatch_queue_t mainQueue = dispatch_get_main_queue(); //获取全局并发队列 dispatch_queue_t otherQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //同步函数(在当前线程中执行,不具备开启新线程的能力) dispatch_sync(otherQueue, ^{ NSLog(@"同步 %@", [NSThread currentThread]); }); //异步函数(在另一条线程中执行,具备开启新线程的能力) dispatch_async(otherQueue, ^{ NSLog(@"异步 %@", [NSThread currentThread]); }); //输出: 当前线程: <NSThread: 0x7f81bac06670>{number = 1, name = main} //输出: 同步 <NSThread: 0x7f81bac06670>{number = 1, name = main} //输出: 异步 <NSThread: 0x7f81bae35be0>{number = 3, name = (null)}
dispatch_after()延迟一段时间把一项任务提交到队列中执行,返回之后就不能取消 常用来在在主队列上延迟执行一项任务
NSLog(@"当前线程 %@", [NSThread currentThread]); //GCD延时调用(主线程)(主队列) dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"GCD延时(主线程) %@", [NSThread currentThread]); }); //GCD延时调用(其他线程)(全局并发队列) dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"GCD延时(其他线程) %@", [NSThread currentThread]); }); //输出: 当前线程 <NSThread: 0x7f8cb9701990>{number = 1, name = main} //输出: GCD延时(主线程) <NSThread: 0x7f8cb9701990>{number = 1, name = main} //输出: GCD延时(其他线程) <NSThread: 0x7f8cb9513ee0>{number = 3, name = (null)}
整个程序运行中,只会执行一次 (默认线程是安全的) dispatch_once() 以线程安全的方式执行且仅执行其代码块一次
for (NSInteger i = 0; i < 10; i++) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"GCD一次性执行(默认线程是安全的)"); }); } //输出: GCD一次性执行(默认线程是安全的)
//使用GCD初始化单例 + (instancetype)sharedManager { static PhotoManager *sharedPhotoManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedPhotoManager = [[PhotoManager alloc] init]; }); return sharedPhotoManager; }
把一项任务提交到队列中多次执行,具体是并行执行还是串行执行由队列本身决定 dispatch_apply不会立刻返回,在执行完毕后才会返回,是同步的调用。
任务1,任务2依次执行,所有任务都执行成功后回到主线程 (效率不高)
NSLog(@"当前线程 %@", [NSThread currentThread]); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //全局并发队列 for (NSInteger i = 0; i < 5; i++) { NSLog(@"任务1 %@", [NSThread currentThread]); } for (NSInteger i = 0; i < 5; i++) { NSLog(@"任务2 %@", [NSThread currentThread]); } dispatch_async(dispatch_get_main_queue(), ^{ //主队列 NSLog(@"主线程执行(刷新UI) %@", [NSThread currentThread]); }); }); //输出: 当前线程 <NSThread: 0x7fa78040b8b0>{number = 1, name = main} //输出: 任务1 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)} //输出: 任务1 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)} //输出: 任务1 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)} //输出: 任务1 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)} //输出: 任务1 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)} //输出: 任务2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)} //输出: 任务2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)} //输出: 任务2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)} //输出: 任务2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)} //输出: 任务2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)} //输出: 任务2 <NSThread: 0x7f9da1416a00>{number = 3, name = (null)} //输出: 主线程(刷新UI) <NSThread: 0x7f9da1705940>{number = 1, name = main}
任务1,任务2同时执行,所有任务都执行成功后回到主线程 (效率高)
NSLog(@"当前线程 %@", [NSThread currentThread]); //(1)创建一个队列组 dispatch_group_t group= dispatch_group_create(); //(2)开启任务1 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ for (NSInteger i = 0; i < 5; i++) { NSLog(@"任务1 %@", [NSThread currentThread]); } }); //(3)开启任务2 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ for (NSInteger i = 0; i < 5; i++) { NSLog(@"任务2 %@", [NSThread currentThread]); } }); //(4)所有任务执行完毕,回到主线程 dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"主线程(刷新UI) %@", [NSThread currentThread]); }); //输出: 当前线程 <NSThread: 0x7fd951704e70>{number = 1, name = main} //输出: 任务1 <NSThread: 0x7ff65a50b4d0>{number = 3, name = (null)} //输出: 任务1 <NSThread: 0x7ff65a50b4d0>{number = 3, name = (null)} //输出: 任务1 <NSThread: 0x7ff65a50b4d0>{number = 3, name = (null)} //输出: 任务2 <NSThread: 0x7ff65a697770>{number = 4, name = (null)} //输出: 任务2 <NSThread: 0x7ff65a697770>{number = 4, name = (null)} //输出: 任务1 <NSThread: 0x7ff65a50b4d0>{number = 3, name = (null)} //输出: 任务2 <NSThread: 0x7ff65a697770>{number = 4, name = (null)} //输出: 任务1 <NSThread: 0x7ff65a50b4d0>{number = 3, name = (null)} //输出: 任务2 <NSThread: 0x7ff65a697770>{number = 4, name = (null)} //输出: 任务2 <NSThread: 0x7ff65a697770>{number = 4, name = (null)} //输出: 主线程(刷新UI) <NSThread: 0x7ff65a406fb0>{number = 1, name = main}
一个任务执行完毕后,再执行下一个任务 主队列是GCD自带的一种特殊的串行队列,放在主队列中的任务,都会放到主线程中执行
//(1)使用dispatch_queue_create函数创建串行队列 //参数1: 队列名称 //参数2: 队列属性 (一般用NULL) dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", NULL); //(2)使用主队列(跟主线程相关联的队列) dispatch_queue_t serialMainQueue = dispatch_get_main_queue();
多个任务并发执行(自动开启多个线程同时执行任务) 并发功能只有在异步(dispatch_async)函数下才有效!!! GCD默认已经提供了全局的并发队列,供整个应用使用,不需要手动创建
多个任务并发执行(自动开启多个线程同时执行任务)
并发功能只有在异步(dispatch_async)函数下才有效!!!
GCD默认已经提供了全局的并发队列,供整个应用使用,不需要手动创建
//(1)使用dispatch_get_global_queue函数获得全局的并发队列 //参数1: 优先级 //参数2: 暂时无用参数 (传0) dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
(开启新线程,并发执行任务)
NSLog(@"当前线程 %@", [NSThread currentThread]); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"任务1 %@", [NSThread currentThread]); }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"任务2 %@", [NSThread currentThread]); }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"任务3 %@", [NSThread currentThread]); }); //输出: 当前线程 <NSThread: 0x7fbe83c067c0>{number = 1, name = main} //输出: 任务1 <NSThread: 0x7fb84160ed90>{number = 3, name = (null)} //输出: 任务3 <NSThread: 0x7fb841752940>{number = 4, name = (null)} //输出: 任务2 <NSThread: 0x7fb8414167b0>{number = 5, name = (null)}
(开启新线程,串行执行任务)
NSLog(@"当前线程 %@", [NSThread currentThread]); //创建串行队列 dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", NULL); dispatch_async(serialQueue, ^{ NSLog(@"任务1 %@", [NSThread currentThread]); }); dispatch_async(serialQueue, ^{ NSLog(@"任务2 %@", [NSThread currentThread]); }); dispatch_async(serialQueue, ^{ NSLog(@"任务3 %@", [NSThread currentThread]); }); //输出: 当前线程 <NSThread: 0x7fc192e05380>{number = 1, name = main} //输出: 任务1 <NSThread: 0x7fc192c16670>{number = 3, name = (null)} //输出: 任务2 <NSThread: 0x7fc192c16670>{number = 3, name = (null)} //输出: 任务3 <NSThread: 0x7fc192c16670>{number = 3, name = (null)}
(不会开启新线程,并发执行任务失效!)
NSLog(@"当前线程 %@", [NSThread currentThread]); dispatch_sync(dispatch_get_global_queue(0, 0), ^{ NSLog(@"任务1 %@", [NSThread currentThread]); }); dispatch_sync(dispatch_get_global_queue(0, 0), ^{ NSLog(@"任务2 %@", [NSThread currentThread]); }); dispatch_sync(dispatch_get_global_queue(0, 0), ^{ NSLog(@"任务3 %@", [NSThread currentThread]); }); //输出: 当前线程 <NSThread: 0x7fa0dbf02e20>{number = 1, name = main} //输出: 任务1 <NSThread: 0x7fa0dbf02e20>{number = 1, name = main} //输出: 任务2 <NSThread: 0x7fa0dbf02e20>{number = 1, name = main} //输出: 任务3 <NSThread: 0x7fa0dbf02e20>{number = 1, name = main}
(不会开启新线程,串行执行任务)
NSLog(@"当前线程 %@", [NSThread currentThread]); //创建串行队列 dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", NULL); dispatch_sync(serialQueue, ^{ NSLog(@"任务1 %@", [NSThread currentThread]); }); dispatch_sync(serialQueue, ^{ NSLog(@"任务2 %@", [NSThread currentThread]); }); dispatch_sync(serialQueue, ^{ NSLog(@"任务3 %@", [NSThread currentThread]); }); //输出: 当前线程 <NSThread: 0x7f8c0b407f00>{number = 1, name = main} //输出: 任务1 <NSThread: 0x7f8c0b407f00>{number = 1, name = main} //输出: 任务2 <NSThread: 0x7f8c0b407f00>{number = 1, name = main} //输出: 任务3 <NSThread: 0x7f8c0b407f00>{number = 1, name = main}
The text was updated successfully, but these errors were encountered:
No branches or pull requests
GCD介绍
术语
注意:
#基本使用
延时执行 dispatch_after()
一次性执行 dispatch_once()
提交 dispatch_apply()
队列
队列组
#串行与并发
串行队列
并发队列
异步函数_并发队列
异步函数_串行队列
同步函数_并发队列
同步函数_串行队列
The text was updated successfully, but these errors were encountered: