目录
一、关于信号量
信号量的主要作用是通过阻塞线程来控制流程顺序。
主要有三个函数:
dispatch_semaphore_t sem = dispatch_semaphore_create(0) :创建信号量
dispatch_semaphore_signal(sem) :信号量+1
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER) : 信号量-1
当信号量为0时执行wait操作会阻塞线程,等到信号量大于0才继续执行。
二、应用
准备
写两个网络请求方法,方便以下应用例子中使用:
- (void)requestTest1Success:(void(^)(BOOL isSuccess))result
{
NSString * urlStr = @"http://121.8.145.4:10096/app_if/getConfig?appID=1";
AFHTTPSessionManager * manager = [AFHTTPSessionManager manager];
// 超时时间
manager.requestSerializer.timeoutInterval = 30;
// 上传的格式(JSON)
manager.requestSerializer = [AFHTTPRequestSerializer serializer];//普通格式
manager.requestSerializer = [AFJSONRequestSerializer serializer];//json格式
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html",@"text/plain", nil];
[manager GET:urlStr parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
result(YES);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
result(NO);
}];
}
- (void)requestTest2Success:(void(^)(BOOL isSuccess))result
{
NSString * urlStr = @"http://121.8.145.4:10096/app_if/getConfig?appID=1";
AFHTTPSessionManager * manager = [AFHTTPSessionManager manager];
// 超时时间
manager.requestSerializer.timeoutInterval = 30;
// 上传的格式(JSON)
manager.requestSerializer = [AFHTTPRequestSerializer serializer];//普通格式
manager.requestSerializer = [AFJSONRequestSerializer serializer];//json格式
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html",@"text/plain", nil];
[manager GET:urlStr parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
result(YES);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@" -- test 2-- fail -- %@",error);
result(NO);
}];
}
1、控制并发数
dispatch_semaphore_t sem = dispatch_semaphore_create(2);
dispatch_queue_t queue = dispatch_queue_create("queue", NULL);
for (int i=0; i<10; i++) {
dispatch_async(queue, ^{
[self requestTest1Success:^(BOOL isSuccess) {
NSLog(@" === %d",i);
dispatch_semaphore_signal(sem);
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
NSLog(@" -- test --");
});
}
设定信号量为2,总任务数为10,当前两个任务在完成时,其他任务是阻塞的,只有完成其中一个才能继续开始第三个任务,依次类推,可以实现并发数的控制,在遇到多图加载之类的情况时可以进行并发数控制。
2、顺序请求接口GCD
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
dispatch_group_async(group, queue, ^{
[self requestTest1Success:^(BOOL isSuccess) {
sleep(2);
NSLog(@" -- test 1--");
dispatch_semaphore_signal(sem);
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
[self requestTest2Success:^(BOOL isSuccess) {
NSLog(@" -- test 2--");
dispatch_semaphore_signal(sem);
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
});
dispatch_group_notify(group, queue, ^{
NSLog(@" -- test 3--");
});
执行结果顺序执行test1,test2,最后执行test3。
执行test1时进行线程阻塞,只是请求完成以后signal信号量+1,才能继续执行下面的任务。
应用场景为:需要顺序执行某些请求,请求结束以后在执行其他操作,通过group和信号量结合操作来实现。
3、顺序请求接口NSOperationQueue
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
NSOperationQueue * queue = [[NSOperationQueue alloc]init];
NSBlockOperation * op1 = [NSBlockOperation blockOperationWithBlock:^{
[self requestTest1Success:^(BOOL isSuccess) {
sleep(2);
NSLog(@" -- test 1--");
dispatch_semaphore_signal(sem);
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}];
NSBlockOperation * op2 = [NSBlockOperation blockOperationWithBlock:^{
[self requestTest2Success:^(BOOL isSuccess) {
NSLog(@" -- test 2--");
dispatch_semaphore_signal(sem);
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}];
[op2 addDependency:op1];
[queue addOperations:@[op1,op2] waitUntilFinished:NO];
用NSOperationQueue可以同样实现。
不过在顺序执行请求的时候,waitUntilFinished 设置成 YES 会阻塞线程,所以需要请求完成以后在执行其他任务时,推荐使用GCD。
三、注意事项
需要注意的是文中的例子是请求接口,afn请求接口会出现新的线程,而dispatch_group在发送请求的时候就表示该任务已经完成,并不能等到接口返回成功,所以需要用信号量来控制,如果是普通的业务逻辑处理就不需要了。