[New learn]GCD的基本使用
https://github.com/xufeng79x/GCDDemo
1.简介
介绍GCD的使用,介绍多种队列与同步异步多种情况下的组合运行情况。
2.基本使用步骤
如果使用GCD则一般也就两个步骤
1.创建/获取执行队列
2.同步或者异步在队列中执行任务 ,通常任务为一个block
3.队列与执行类型(同步或者异步)的组合运行情况
GCD的队列分为串行队列和并发队列,这两种队里都可以自行创建。
除了能够自行创建队列外,系统中已经存在了主队列和全局队列,这两个队列我们可以直接获取使用。
GCD的任务执行方式有分为同步和异步两种。所以根据队列类型和执行方式我们可以排列组合进行选择,下面我们将对这种组合
加以测试来探索他们的不同表现。
执行方式/队列类型 | 自建串行队列 | 自建并发队列 | 主队列 | 全局队列 |
同步 |
||||
异步 |
3.1 自建串行队列+同步执行
/** * 串行+同步方式执行任务 * 任务顺序:先进先出 * 线程启动方式:不开启新线程,全部在当前线程中执行 */ -(void) test1 { // 创建串行队列 dispatch_queue_t queue = dispatch_queue_create("xf", DISPATCH_QUEUE_SERIAL); // 循环调用,确定任务的放置于启动顺序 ; i < ; i++) { // 同步方式启动任务 dispatch_sync(queue,^{ NSLog(@"execute task : %d in thread : %@", i, [NSThread currentThread]); }); } NSLog(@"%@", @"完成!"); }
执行结果:
-- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] 完成!
总结:
/** * 串行+同步方式执行任务 * 任务顺序:先进先出 * 线程启动方式:不开启新线程,全部在当前线程中执行 */
3.2 自建串行队列+异步执行
/** * 串行+异步方式执行任务 * 任务顺序:先进先出 * 线程启动方式:开启新线程且只开启一个新线程,全部在新线程中执行 */ -(void) test2 { // 创建串行队列 dispatch_queue_t queue = dispatch_queue_create("xf", DISPATCH_QUEUE_SERIAL); // 循环调用,确定任务的放置于启动顺序 ; i < ; i++) { // 同步方式启动任务 dispatch_async(queue,^{ NSLog(@"execute task : %d in thread : %@", i, [NSThread currentThread]); }); } NSLog(@"%@", @"完成!"); }
结果:
-- :::] 完成! -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)}
总结:
/** * 串行+异步方式执行任务 * 任务顺序:先进先出 * 线程启动方式:开启新线程且只开启一个新线程,全部在新线程中执行 */
3.3 自建并发队列+同步执行
/** * 并发队列+同步方式执行任务 * 任务顺序:先进先出 * 线程启动方式:不开启新线程,全部在当前线程中执行 */ -(void) test3 { // 创建队列 dispatch_queue_t queue = dispatch_queue_create("xf", DISPATCH_QUEUE_CONCURRENT); // 循环调用,确定任务的放置于启动顺序 ; i < ; i++) { // 启动任务 dispatch_sync(queue,^{ NSLog(@"execute task : %d in thread : %@", i, [NSThread currentThread]); }); } NSLog(@"%@", @"完成!"); }
结果:
-- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] 完成!
总结:
/** * 并发队列+同步方式执行任务 * 任务顺序:先进先出 * 线程启动方式:不开启新线程,全部在当前线程中执行 */
3.4 自建并发队列+异步执行
/** * 并发队列+异步方式执行任务 * 任务顺序:无序 * 线程启动方式:开启多个线程,在多个线程中可以同时执行多个任务 */ -(void) test4 { // 创建队列 dispatch_queue_t queue = dispatch_queue_create("xf", DISPATCH_QUEUE_CONCURRENT); // 循环调用,确定任务的放置于启动顺序 ; i < ; i++) { // 启动任务 dispatch_async(queue,^{ NSLog(@"execute task : %d in thread : %@", i, [NSThread currentThread]); }); } NSLog(@"%@", @"完成!"); }
结果:
-- :::] 完成! -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)}
总结:
/** * 并发队列+异步方式执行任务 * 任务顺序:无序 * 线程启动方式:开启多个线程,在多个线程中可以同时执行多个任务 */
接下来我们来测试一下两个特殊的队列:主队列和全局队列
主队列:负责在主线程上调度任务,顺序执行其中任务。其中的任务不会运行与子线程,换句话说无论是同步还是异步都不会开子线程。
3.5 主队列+同步执行
/** * 主队列+同步方式执行任务 * 任务顺序:卡死 * 线程启动方式:卡死 */ -(void) test5 { // 创建队列 dispatch_queue_t queue = dispatch_get_main_queue(); // 循环调用,确定任务的放置于启动顺序 ; i < ; i++) { // 启动任务 dispatch_sync(queue,^{ NSLog(@"execute task : %d in thread : %@", i, [NSThread currentThread]); }); } NSLog(@"%@", @"完成!"); }
结果:
无
总结:
/** * 主队列+同步方式执行任务 * 任务顺序:卡死 * 线程启动方式:卡死 */
3.6 主队列+异步执行
/** * 主队列+异步方式执行任务 * 任务顺序:先进先出 * 线程启动方式:不开启新线程,只在主线程中执行(需要等到主线程中当前任务完成后再执行后续任务,可观察到先打印“完成“) */
-(void) test6 { // 创建队列 dispatch_queue_t queue = dispatch_get_main_queue(); // 循环调用,确定任务的放置于启动顺序 ; i < ; i++) { // 启动任务 dispatch_async(queue,^{ NSLog(@"execute task : %d in thread : %@", i, [NSThread currentThread]); }); } NSLog(@"%@", @"完成!"); }
结果:
-- :::] 完成! -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main}
总结:
/** * 主队列+异步方式执行任务 * 任务顺序:先进先出 * 线程启动方式:不开启新线程,只在主线程中执行(需要等到主线程中当前任务完成后再执行后续任务,可观察到先打印“完成”) */
3.7 全局队列+同步执行
/** * 全局队列+同步方式执行任务 * 任务顺序:先进先出 * 线程启动方式:不开启新线程,只在主线程中执行 */ -(void) test7 { // 创建队列 dispatch_queue_t queue = dispatch_get_global_queue(, ); // 循环调用,确定任务的放置于启动顺序 ; i < ; i++) { // 启动任务 dispatch_sync(queue,^{ NSLog(@"execute task : %d in thread : %@", i, [NSThread currentThread]); }); } NSLog(@"%@", @"完成!"); }
结果:
-- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] execute task : , name = main} -- :::] 完成!
总结:
/** * 全局队列+同步方式执行任务 * 任务顺序:先进先出 * 线程启动方式:不开启新线程,只在主线程中执行 */
3.8 全局队列+异步执行
/** * 全局队列+异步方式执行任务 * 任务顺序:无序 * 线程启动方式:开启多个新线程,不同任务可在不同线程中并发执行 */ -(void) test8 { // 创建队列 dispatch_queue_t queue = dispatch_get_global_queue(, ); // 循环调用,确定任务的放置于启动顺序 ; i < ; i++) { // 启动任务 dispatch_async(queue,^{ NSLog(@"execute task : %d in thread : %@", i, [NSThread currentThread]); }); } NSLog(@"%@", @"完成!"); }
结果:
-- :::] 完成! -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)} -- :::] execute task : , name = (null)}
总结:
/** * 全局队列+异步方式执行任务 * 任务顺序:无序 * 线程启动方式:开启多个新线程,不同任务可在不同线程中并发执行 */
4.至此对于GCD的一般用法总结如下:
执行方式/队列类型 | 自建串行队列 | 自建并发队列 | 主队列 | 全局队列 |
同步 |
1.不开启新线程 2.先进先出顺序执行 |
1.不开启新线程 2.先进先出顺序执行 |
卡死 |
1.不开启新线程 2.先进先出顺序执行 |
异步 |
1.开启新线程,且只开启一个新线程。 2.先进先出顺序执行,且只在新线程中执行 |
1.开启多个线程,任务可在多个线程中并发执行 2.无序执行 |
1.不开启新线程,只在主线程中执行 2.先进先出顺序执行 |
1.开启多个线程,任务可在多个线程中并发执行 2.无序执行 |
有此我们可以看出:
1.同步执行方式都不会新建线程。
2.当队列为串行队列,则在异步执行方式下也只会开启一个线程,因为队列性质决定,开启多个线程也是徒劳无功。
3.主队列只能在主线程下执行。
3.全局队列的表现和自建并发队列一致,所以平时可以直接使用全局队列。
5.更进一步
我们看到GCD中存在卡死的现象,那么什么时候回出现这种情况呢?下一篇博文[New learn]GCD的卡死现象分析研究继续分析研究。
最新文章
- js实现文件上传
- Python学习路程day11
- Kerberos认证原理简介
- 在Web api2 中传递复杂参数的一点心得
- Android Studio 和 Gradle
- nginx服务器应用中遇到的两个问题
- 【转载】hadoop的版本问题
- python打印详细的异常信息
- servlet读取cookie问题
- php对象的高级特性
- ​c++ 调用DLL函数,出现错误
- Windows Internals 笔记——关联性
- python 解析命令行
- kali安装配置ftp
- phothoshop 快捷键
- Flutter - Json序列化
- bitmq集群高可用测试
- C++中set的用法
- lua 函数基础
- SSM框架中,配置数据库连接的问题
热门文章
- javascript中的this作用域详解
- [洛谷P2495][SDOI2011]消耗战
- [bzoj] 2049 洞穴勘探 || LCT
- layui中对表格操作按钮集的判断
- mysql绿色版安装,多实例安装
- wamp环境介绍
- (转)Django发送html邮件
- easing.js让页面动画丰富起来
- 确保web安全的https、确认访问用户身份的认证(第七章、第八章)
- JavaScript之typedof,instanceof,Array.isArray()