在进行项目开发时经常会遇到这样一个场景:当多个请求完成时,最后执行某个业务逻辑。一看上去这就是一个多线程控制同步的问题,常见的解决方案有三种。
- 每个请求定义一个变量,然后在每个请求执行完后的block里执行最后执行业务逻辑的方法,方法里必然有着这几个变量的真判断。
- 使用队列NSOperationQueue控制多线程同步。
- 使用信号量dispatch_semaphore_t控制多线程同步。
- 使用进程同步dispatch_group_t控制多线程同步。
比较及实现方式
第一种看上去很粗浅,就是每次请求就去判断一次各个变量,都通过了表示请求完成了,然后执行最后的业务逻辑。当然这种最好写,但是会加大内存开销和业务复杂度,一方面是有几个请求就得定义几个变量,程序运行时需要进行内存分配,另外还要维护每个变量的真假业务逻辑,如果存在刷新之类的操作更是如此,更有甚者,如果是几十上百个请求,难道要定义几十上百个变量,所以对于简单的多线程请求,稍微多一些或者复杂一些的不建议使用。不过,现在这种方式一般见不到。
第二种队列NSOperationQueue面向对象方式,多用于请求之间存在依赖关系,如果不存在依赖关于请求的完成无法控制,所以不存在依赖则这种方式一般不建议使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| NSBlockOperation *operation_1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"1"); [self loadUserFriendsData]; }]; NSBlockOperation *operation_2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"2"); [self loadBalaceData]; }]; NSBlockOperation *operation_3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"3"); [self loadUserData]; }];
[operation_2 addDependency:operation_3]; [operation_1 addDependency:operation_2];
NSOperationQueue *queue = [[NSOperationQueue alloc]init]; [queue addOperations:@[operation_3,operation_2,operation_1] waitUntilFinished:NO];
|
- 第三种使用信号量dispatch_semaphore_t和使用dispatch_group_t有异曲同工之妙,所以这里直接上代码,怎么使用。
1 2 3 4 5 6
| dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_semaphore_signal(sema);
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| (void)request2{ //创建信号量并设置计数默认为0 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); NSDictionary * para ;//参数 具体部分我就不暴露了 [WJFCollection postWithUrlString:@"url" Parameter:para success:^(id responseObject) { //只要在这里发送信号 dispatch_semaphore_signal(semaphore); } failure:^(NSError *error) { //只要在这里发送信号 dispatch_semaphore_signal(semaphore); NSLog(@"%@",error); }]; //若计数为0则一直等待 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); }
|
- 第四种使用dispatch_group_t,使用方式如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self requestData]; }) ; dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self requestData]; }) ; dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self requestData]; }) ; dispatch_group_notify(group, dispatch_get_main_queue(), ^{
[self showUserView]; });
|
1 2 3 4 5 6 7 8 9 10
| - (void)requestData { dispatch_group_enter(self.group); WeakSelf [self.VMModel request:^(id model, NSError * _Nonnull error) { StrongSelf if (strongSelf) { dispatch_group_leave(strongSelf.group); } }]; }
|
dispatch_semaphore和dispatch_group在使用方式上大同小异,但是dispatch_semaphore相对而言更涉及到底层,越底层使用起来越灵活,自定义程度越高,但是使用起来就会越复杂,而dispatch_group是在信号量dispatch_semaphore_t基础上进行的一层封装,所以使用起来方便一些。从使用对象来说,dispatch_group更加针对的是任务、进程而非线程,所以整体性处理起来更快捷。关于两者的层级请看dispatch_group_leave的源码使用。
1 2 3 4 5 6 7 8 9 10 11 12
| void dispatch_group_leave(dispatch_group_t dg) { dispatch_semaphore_t dsema = (dispatch_semaphore_t)dg; dispatch_atomic_release_barrier(); long value = dispatch_atomic_inc2o(dsema, dsema_value); if (slowpath(value == LONG_MIN)) { DISPATCH_CLIENT_CRASH("Unbalanced call to dispatch_group_leave()"); } if (slowpath(value == dsema->dsema_orig)) { (void)_dispatch_group_wake(dsema); } }
|