runtime.runloopiOS多线程

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");
上一篇 下一篇

猜你喜欢

热点阅读