GCD的几种特殊用法
2021-06-21 本文已影响0人
傲骨天成科技
一、多个网络请求完成后如何执行下一步?
1.解法一:
使用GCD的dispatch_group_t
创建一个dispatch_group_t
每次网络请求前先dispatch_group_enter,请求回调后再dispatch_group_leave,enter和leave必须配合使用,有几次enter就要有几次leave,否则group会一直存在。
当所有enter的block都leave后,会执行dispatch_group_notify的block。
NSString *str = @"https://mp.weixin.qq.com/s/zppYYndyYsq_lxenrJOCnw";
NSURL *url = [NSURL URLWithString:str];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession];
// 1.创建dispatch_group
dispatch_group_t downloadGroup = dispatch_group_create();
for (int i=0; i<10; i++) {
// 2.进入dispatch_group
dispatch_group_enter(downloadGroup);
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error != nil) {
NSLog(@"错误:%@",error);
}
NSLog(@"%@=%d---%d",[NSThread currentThread],i,i);
// 3. 离开dispatch_group
dispatch_group_leave(downloadGroup);
}];
[task resume];
}
// 4.完成dispatch_group最后的通知,之后执行
dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
NSLog(@"end");
});
2.解法2:
使用GCD的信号量dispatch_semaphore_t
dispatch_semaphore信号量为基于计数器的一种多线程同步机制。如果semaphore计数大于等于1,计数-1,返回,程序继续运行。如果计数为0,则等待。dispatch_semaphore_signal(semaphore)为计数+1操作,dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)为设置等待时间,这里设置的等待时间是一直等待。
创建semaphore为0,等待,等10个网络请求都完成了,dispatch_semaphore_signal(semaphore)为计数+1,然后计数-1返回
__block int count = 0;
NSString *str = @"https://mp.weixin.qq.com/s/zppYYndyYsq_lxenrJOCnw";
NSURL *url = [NSURL URLWithString:str];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession];
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
for (int i=0; i<10; i++) {
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@:%d---%d",[NSThread currentThread],i,i);
count++;
if (count==10) {
dispatch_semaphore_signal(sem);
count = 0;
}
}];
[task resume];
}
NSLog(@"之前");
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
NSLog(@"之后");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"end");
});
二、多个网络请求顺序执行后如何执行下一步?
异步执行,进行同步操作
使用信号量semaphore
每一次遍历,都让其dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER),这个时候线程会等待,阻塞当前线程,直到dispatch_semaphore_signal(sem)调用之后
NSString *str = @"http://www.jianshu.com/p/6930f335adba";
NSURL *url = [NSURL URLWithString:str];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession];
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
for (int i=0; i<10; i++) {
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%d---%d",i,i);
sleep(1);
dispatch_semaphore_signal(sem);
}];
[task resume];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"end");
});
三、设置最大并发数
/// 最多只有3个任务执行
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
// 创建一个并发队列
dispatch_queue_t queue = dispatch_queue_create("并发队列", DISPATCH_QUEUE_CONCURRENT);
// 总共有6个任务,一次执行3个任务,3个任务结束,接着再执行3个任务,直到任务都完成
for (int i = 0; i < 6; i++) {
dispatch_async(queue, ^{
NSLog(@"我是最开始");
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"任务%d 开始",i);
[NSThread sleepForTimeInterval:2];
NSLog(@"任务%d 结束",i);
dispatch_semaphore_signal(semaphore);
});
}
四、dispatch group异步线程同步执行
// dispatch_group_enter(group); 相当于进入group block 加1
// dispatch_group_leave(group); //相当于退出group block 减1
// 这两个方法是为了保证group block中即使有异步block,也能准确的调用dispatch_group_notify
//只有dispatch_group_enter,dispatch_group_leave 成对调用时才能最终调用dispatch_group_notify
dispatch_queue_t queue = dispatch_queue_create("并发队列", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"任务1 开始 线程:%@",[NSThread currentThread]);
dispatch_async(dispatch_queue_create("并发队列", DISPATCH_QUEUE_CONCURRENT), ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"任务1 结束 线程:%@",[NSThread currentThread]);
dispatch_semaphore_signal(semaphore);
dispatch_group_leave(group);
});
});
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"任务2 开始 线程:%@",[NSThread currentThread]);
dispatch_async(dispatch_queue_create("并发队列", DISPATCH_QUEUE_CONCURRENT), ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"任务2 结束 线程:%@",[NSThread currentThread]);
dispatch_semaphore_signal(semaphore);
dispatch_group_leave(group);
});
});
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"任务3 开始 线程:%@",[NSThread currentThread]);
dispatch_async(dispatch_queue_create("并发队列", DISPATCH_QUEUE_CONCURRENT), ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"任务3 结束 线程:%@",[NSThread currentThread]);
dispatch_semaphore_signal(semaphore);
dispatch_group_leave(group);
});
});
dispatch_group_notify(group, queue, ^{
NSLog(@"group内的三个任务执行完毕了");
});
五、死锁
1.死锁一
// 这是一个串行队列
dispatch_queue_t queue = dispatch_queue_create("串行队列", DISPATCH_QUEUE_SERIAL);
NSLog(@"开始");
dispatch_sync(queue, ^{
NSLog(@"1");
dispatch_async(queue, ^{
NSLog(@"2");
});
NSLog(@"3");
[NSThread sleepForTimeInterval:3];
});
[NSThread sleepForTimeInterval:1];
NSLog(@"end");
2.死锁二
// 2个任务相互等待造成死锁
dispatch_queue_t queue = dispatch_queue_create("串行队列", DISPATCH_QUEUE_SERIAL);
NSLog(@"开始");
dispatch_async(queue, ^{ // block1
// NSLog(@"1");
dispatch_sync(queue, ^{ // block2
NSLog(@"2");
});
// NSLog(@"3");
});
// NSLog(@"end");