首页 文章 精选 留言 我的

精选列表

搜索[主从同步],共10000篇文章
优秀的个人博客,低调大师

用GCD线程组与GCD信号量将异步线程转换为同步线程

有时候我们会碰到这样子的一种情形: 同时获取两个网络请求的数据,但是网络请求是异步的,我们需要获取到两个网络请求的数据之后才能够进行下一步的操作,这个时候,就是线程组与信号量的用武之地了. #import "ViewController.h" #import <AFNetworking.h> @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self getNetworkingData]; } - (void)getNetworkingData{ NSString *appIdKey = @"8781e4ef1c73ff20a180d3d7a42a8c04"; NSString* urlString_1 = @"http://api.openweathermap.org/data/2.5/weather"; NSString* urlString_2 = @"http://api.openweathermap.org/data/2.5/forecast/daily"; NSDictionary* dictionary =@{@"lat":@"40.04991291", @"lon":@"116.25626162", @"APPID" : appIdKey}; // 创建组 dispatch_group_t group = dispatch_group_create(); // 将第一个网络请求任务添加到组中 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 创建信号量 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); // 开始网络请求任务 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; [manager GET:urlString_1 parameters:dictionary progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"成功请求数据1:%@",[responseObject class]); // 如果请求成功,发送信号量 dispatch_semaphore_signal(semaphore); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"失败请求数据"); // 如果请求失败,也发送信号量 dispatch_semaphore_signal(semaphore); }]; // 在网络请求任务成功之前,信号量等待中 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); }); // 将第二个网络请求任务添加到组中 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 创建信号量 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); // 开始网络请求任务 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; [manager GET:urlString_2 parameters:dictionary progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"成功请求数据2:%@",[responseObject class]); // 如果请求成功,发送信号量 dispatch_semaphore_signal(semaphore); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"失败请求数据"); // 如果请求失败,也发送信号量 dispatch_semaphore_signal(semaphore); }]; // 在网络请求任务成功之前,信号量等待中 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); }); dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"完成了网络请求,不管网络请求失败了还是成功了。"); }); } @end 打印结果: 2016-03-15 04:01:53.279 NetWorking[83611:1508240] 成功请求数据1:__NSCFDictionary2016-03-15 04:01:53.280 NetWorking[83611:1508240] 成功请求数据2:__NSCFDictionary2016-03-15 04:01:53.281 NetWorking[83611:1508287] 完成了网络请求,不管网络请求失败了还是成功了。 为了和上面形成对比,我特地将所有的信号量的代码全部去除,但是保留GCD线程组的使用,然后运行看打印结果。 #import "ViewController.h" #import <AFNetworking.h> @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self getNetworkingData]; } - (void)getNetworkingData{ NSString *appIdKey = @"8781e4ef1c73ff20a180d3d7a42a8c04"; NSString* urlString_1 = @"http://api.openweathermap.org/data/2.5/weather"; NSString* urlString_2 = @"http://api.openweathermap.org/data/2.5/forecast/daily"; NSDictionary* dictionary =@{@"lat":@"40.04991291", @"lon":@"116.25626162", @"APPID" : appIdKey}; // 创建组 dispatch_group_t group = dispatch_group_create(); // 将第一个网络请求任务添加到组中 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 开始网络请求任务 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; [manager GET:urlString_1 parameters:dictionary progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"成功请求数据1:%@",[responseObject class]); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"失败请求数据"); }]; }); // 将第二个网络请求任务添加到组中 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 开始网络请求任务 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; [manager GET:urlString_2 parameters:dictionary progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"成功请求数据2:%@",[responseObject class]); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"失败请求数据"); }]; }); dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"完成了网络请求,不管网络请求失败了还是成功了。"); }); } @end 打印结果: 2016-03-15 04:05:09.378 NetWorking[83698:1510242] 完成了网络请求,不管网络请求失败了还是成功了。2016-03-15 04:05:10.185 NetWorking[83698:1510096] 成功请求数据1:__NSCFDictionary2016-03-15 04:05:10.186 NetWorking[83698:1510096] 成功请求数据2:__NSCFDictionary 看到这个打印结果,我们似乎有点看不懂了,难道notify线程组没用了?notify不是会在组中的异步任务执行完毕了才会执行么?这是什么情况? 下面我在上面的代码基础上添加了第33、38、39、49、54、55行代码(也就是下面红色高亮的几行代码,都是打印当前线程),然后我们再来看看打印结果: #import "ViewController.h" #import <AFNetworking.h> @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self getNetworkingData]; } - (void)getNetworkingData{ NSString *appIdKey = @"8781e4ef1c73ff20a180d3d7a42a8c04"; NSString* urlString_1 = @"http://api.openweathermap.org/data/2.5/weather"; NSString* urlString_2 = @"http://api.openweathermap.org/data/2.5/forecast/daily"; NSDictionary* dictionary =@{@"lat":@"40.04991291", @"lon":@"116.25626162", @"APPID" : appIdKey}; // 创建组 dispatch_group_t group = dispatch_group_create(); // 将第一个网络请求任务添加到组中 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 开始网络请求任务 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; [manager GET:urlString_1 parameters:dictionary progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"%@",[NSThread currentThread]); NSLog(@"成功请求数据1:%@",[responseObject class]); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"失败请求数据"); }]; NSLog(@"%@",[NSThread currentThread]); NSLog(@"AFN网络请求框架请求完毕"); }); // 将第二个网络请求任务添加到组中 dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 开始网络请求任务 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; [manager GET:urlString_2 parameters:dictionary progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"%@",[NSThread currentThread]); NSLog(@"成功请求数据2:%@",[responseObject class]); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"失败请求数据"); }]; NSLog(@"%@",[NSThread currentThread]); NSLog(@"AFN网络请求框架请求完毕"); }); dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"完成了网络请求,不管网络请求失败了还是成功了。"); }); } @end 打印结果(温馨提示:请求数据可能会出现失败,因为这个网络请求的url是国外的服务器,但是没关系,不要在意这个细节,打印顺序还是一样的): 2016-03-15 04:30:07.406 NetWorking[84306:1523047] {number = 2, name = (null)}2016-03-15 04:30:07.406 NetWorking[84306:1523048] {number = 3, name = (null)}2016-03-15 04:30:07.407 NetWorking[84306:1523047] AFN网络请求框架请求完毕2016-03-15 04:30:07.407 NetWorking[84306:1523048] AFN网络请求框架请求完毕2016-03-15 04:30:07.407 NetWorking[84306:1523075] 完成了网络请求,不管网络请求失败了还是成功了。2016-03-15 04:30:08.239 NetWorking[84306:1523016] {number = 1, name = main}2016-03-15 04:30:08.239 NetWorking[84306:1523016] 成功请求数据1:__NSCFDictionary2016-03-15 04:30:08.240 NetWorking[84306:1523016] {number = 1, name = main}2016-03-15 04:30:08.240 NetWorking[84306:1523016] 成功请求数据2:__NSCFDictionary 总结:网络请求然后处理响应数据是个耗时的操作,也是我们开发中常见的一种情形,在网络请求以及处理响应数据操作完毕之后我们在执行别的操作这样的过程也是我们开发中常见的情形。根据第三部分代码(没有使用信号量的代码)打印结果的顺序,我们可以知道,网络请求的任务是提交给子线程异步处理了,网络请求这样的任务也就快速执行完毕了,但是网络请求是一个任务,处理收到的网络响应又是一个任务,注意不要把这两个过程混为一谈。而收到网络响应以及处理返回响应的数据并不是在子线程中执行的,我们通过在回调响应处理的block(比如48~53行之间就有两个block)中打印当前线程,会发现回调响应处理的block是在主线程中被执行的。 如果读者很熟悉block回调这种通信机制的话,就不难理解,这个回调响应的block真正被调用执行的地方应该是AFN框架的底层代码,AFN 底层代码,是在获取到最终数据后,执行回调操作,此时,才能拿到相应数据,而这个处理网络响应的过程,AFN底层最终是这么做的: 也就是说,seccess和failure都是在主线中异步任务中执行的。 那么,这时候,如果我们需要确定这个主线程中收到网络响应的数据被处理操作结束之后,才最后执行我们需要最后的操作的话,仅仅依靠线程组看来是不够的,所以很少用到的GCD信号量就有了用武之地了。 当然,以上代码如果不用GCD线程组,只用GCD的信号量来处理,也是可以的,这个就留给大家自己探究吧。 最后再简化总结一下:信号量的使用前提是,想清楚你需要处理哪个线程等待,又要哪个线程继续执行,然后使用信号量。 比如上面的AFN网络请求的示例,block回调是在main主线程中执行的,而get请求是在自己创建的异步子线程中执行的。所以按照需求,就需要自己创建的异步子线程等待main主线程中的block执行完了之后再执行。所以异步子线程需要信号量wait,main主线程就设置signal发送信号量。

优秀的个人博客,低调大师

Bee1.17 同时支持 JDBC、安卓和鸿蒙;SQL Server 分页、JPA 支持(同步 Maven)

ORM Bee同时支持JDBC,安卓Android和鸿蒙HarmonyOS;比传统ORM有更好的运行性能;SQL Server分页全面支持; 在 Harmony 和 Android 两个环境 , 可以用同一套 Bee 代码访问 DB, 提高代码重用,节省人力物。 Bee,互联网新时代的 Java ORM 工具,更快、更简单、更自动,开发速度快,运行快,更智能! 更新功能列表: V1.17 (2022・中秋) 新增功能: 1)SqlServer支持start,size两个参数分页 2)事务注解Tran及提供与AOP协调的默认实现;支持在类级别使用 3)支持Android(安卓)直接使用Bee访问SQLite数据库;Bee增加Android ORM功能. 4)支持HarmonyOS(鸿蒙)直接使用Bee访问SQLite数据库;Bee增加HarmonyOS ORM功能.在Harmony和Android两个环境,可以用同一套Bee代码访问DB,提高代码重用,节省人力物力! 5)支持Android日志:android.util.Log 6)支持HarmonyOS日志:ohos.hiviewdfx.HiLog 7)主键支持名称不叫"id",类型除了Long,可以是Integer或String 8)支持用注解定义主键自动生成,主键值生成注解:GenId,GenUUID 9)@Column添加默认实现(强烈建议:在新系统中不要使用该注解) 10)@Table,@Column,@PrimaryKey(@Id),@Ignore(@Transient)可以兼容JPA相应注解(在AnnoAdapter接口定义) 11)字段名称引用类(默认格式:实体名_F(自动生成))增加ALL_NAMES属性,可一次获取实体的所有字段值 12)Ddl.java支持创建索引(normal,unique),联合主键 13)动态获取JdbcToJavaType 14)命名转换增加种类4(DbUpperAndJavaLower):数据库使用大写字母,Java使用小写字母;忽略大小写,使用的字符是一样的 15)同时使用多种命名时,缓存添加TranslateType部分 16)分布式id生成器,支持设置起始年份:bee.distribution.genid.startYear 优化与增强: 1)增强:GenBean生成Javabean,当id是BigDecimal时,重置为Long型 2)优化GenBean,支持都使用默认配置 3)Ddl: 优化创建表流程 4)多数据源环境下,增加日志提示当前使用的是哪个数据源名称 5)分页查询,当获取一页的数据量size为0时,直接返回emptyList 6)增强:SQLite日期类型 (date) 匹配转换支持 7)优化缓存 8)condition.op(fieldName, Op.in, Value)增加支持List,Set,Number Array,单个Number元素 9)condition.opOn(fieldName, Op.in, Value) Value限定只支持Number和String 10)增强:like;Op添加likeLeft,likeRight,likeLeftRight(参数值由框架负责转义);打印SQL日志作相应转义 11)增强:ExcelReader数据列数目动态计算 12)增强:SQLite日期类型 (date) 匹配转换支持 13)链式编程SelectImpl,UpdateImpl调整字段检测. fixed bug: 1)level 2缓存判断;TypeHandlerRegistry返回值类型转换 2)拦截器对象不使用原型模式产生脏数据,改为原型模式 参考实例(部分): Android 环境使用 Bee https://my.oschina.net/u/4111850/blog/5538992 HarmonyOS 鸿蒙使用 ORM Bee 访问数据库实例 https://my.oschina.net/u/4111850/blog/5542608 Bee 事务注解 @Tran 使用实例 https://my.oschina.net/u/4111850/blog/5561350 Bee 的约定与自定义 https://my.oschina.net/u/4111850/blog/5551862 同时使用不同数据源和不同命名转换实例 https://my.oschina.net/u/4111850/blog/5558755 模糊查询 like 用法实例 (Bee) https://my.oschina.net/u/4111850/blog/5560414 更多使用实例: https://gitee.com/automvc/bee-exam https://github.com/automvc/bee-exam Bee 架构图: Bee是一个简单,易用,功能强大,开发速度快,编码少的 JAVA ORM 框架。连接,事务都可以由 Bee 框架负责管理.Bee 简化了与 DB 交互的编码工作量,是编码复杂度为O(1)的 Java 框架! (技术交流 扣群:992650213 ; 更多设计思想,请关注微信公众号:软件设计活跃区) Bee 简单易用:单表操作、多表关联操作,可以不用写 sql, 极少语句就可以完成 SQL 操作;概念简单,10 分钟即可入门。 Bee 功能强大:复杂查询也支持向对象方式,分页查询性能更高,一级缓存即可支持个性化优化;具有分布式特性。高级要求,还可以方便自定义 SQL 语句。 下期功能预告: Bee 2.0 Shading 具有分片功能的分库分表 ORM, 即将要与大家见面了!期待大家的踊跃参与! 码云上的项目首页: https://gitee.com/automvc/bee https://gitee.com/automvc/bee-springboot github: https://github.com/automvc/bee

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册