ios中经常出现多线程并发的情况,其中这里又分很多种情况:

1、进某页面要发四个请求,四个请求之间无影响

     分析:四个请求,考虑到效率,用异步并行,最多发四个接口,按一般方法处理即可。

     代码如下:也可见示例代码requestFourPicTestOne方法

{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    for (NSInteger index = 0; index < 4; index ++) {
        dispatch_async(queue, ^{
            NSLog(@"currentThreadcurrentThread:%@",[NSThread currentThread]);
            NSURL *url = [NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"];
            NSURLSession *session = [NSURLSession sharedSession];
            NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    UIImage *image = [UIImage imageWithData:data];
                    switch (index) {
                        case 0:
                            self.imageOne.image = image;
                            break;
                        case 1:
                            self.imageTwo.image = image;
                            break;
                        case 2:
                            self.imageThree.image = image;
                            break;
                        case 3:
                            self.imageFour.image = image;
                            break;
                        default:
                            break;
                    }
                    NSLog(@"这里是主线程:%@",[NSThread currentThread]);
                });
            }];
            [task resume];
        });
    }
}

2、进某页面要发四个请求,四个请求之间无影响,等所有请求回来刷新界面

     分析:只有四个请求,同时执行任务的线程数不必考虑;请求之间无影响,不用考虑数据同步问题,用异步并行(group_enter,group_leave);等所有请求返回数据再刷新,需要等所有回调数据都回来,当然error的情况也包括在内(group_notify)

     代码如下:见示例代码 requestFourPicTestTwo 方法

{
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_t group = dispatch_group_create();
    for (NSInteger index = 0; index < 4; index ++) {
dispatch_group_enter(group);
        dispatch_async(queue, ^{
            NSLog(@"currentThreadcurrentThread:%@",[NSThread currentThread]);
            NSURL *url = [NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"];
            NSURLSession *session = [NSURLSession sharedSession];
            NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                UIImage *iamge = [UIImage imageWithData:data];
                [self.imageArray addObject:iamge];
dispatch_group_leave(group);
            }];
            [task resume];
        });
    }
 dispatch_group_notify(group, queue, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            for (NSInteger index = 0; index < self.imageArray.count; index ++) {
                switch (index) {
                    case 0:
                        self.imageOne.image = self.imageArray[index];
                        break;
                    case 1:
                        self.imageTwo.image = self.imageArray[index];
                        break;
                    case 2:
                        self.imageThree.image = self.imageArray[index];
                        break;
                    case 3:
                        self.imageFour.image = self.imageArray[index];
                        break;
                    default:
                        break;
                }
                if (index > 0) {
                    self.bigImage = [self addImageView:self.imageArray[index -1] toImage:self.imageArray[index]];
                }
            }
            self.bigImageView.image = self.bigImage;
            NSLog(@"这里是主线程:%@",[NSThread currentThread]);
        });
    });
}

3、进某页面要发四个请求,其中某个请求的请求参数是另一个请求结果的返回字段(请求2依赖于请求1的回调结果)(用全局变量signalStr取值的变化,说明发请求2的时候请求1的回调结果是否已经返回)

    分析:任务3、任务4分别用两条线程x、y异步执行;任务1、2放在一条线程z按顺序执行;为保证最大效率并且线程x、y、z之间是异步的。

 代码1如下: 也可见实例代码requestFourPicTestThreeWrongSync方法

{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_queue_t syncQueue = dispatch_queue_create("ayncQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{//最优解
        //请求1
            dispatch_async(syncQueue, ^{
                NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                    UIImage *image = [UIImage imageWithData:data];
                    NSLog(@"请求1的回调结果:%@",[NSThread currentThread]);
                    self.signalStr = @"22";
                }];
                [task resume];
                NSLog(@"请求1发出去了:%@",[NSThread currentThread]);
            });
        //请求2
            dispatch_async(syncQueue, ^{
                NSLog(@"请求2,signalStr:%@ == %@",self.signalStr,[NSThread currentThread]);
                NSURLSessionDataTask *taskW = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                    UIImage *image = [UIImage imageWithData:data];
                    NSLog(@"请求2的结果:%@ == %@",self.signalStr,[NSThread currentThread]);
                }];
                [taskW resume];
                NSLog(@"这里发完请求2了");
            });
        
    });
    //请求3,4
    for (NSInteger index = 0; index < 2; index ++) {
        dispatch_async(queue, ^{
            NSLog(@"请求3、4发出去了:%@",[NSThread currentThread]);
            NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                UIImage *image = [UIImage imageWithData:data];
                NSLog(@"被请求3或请求4的回调结果:%@",[NSThread currentThread]);
            }];
            [task resume];
        });
    }
}

打印结果显示:

2018-10-23 17:56:19.621427+0800 多请求并发[12865:1232114] 请求3、4发出去了:<NSThread: 0x600003c95100>{number = 4, name = (null)}
2018-10-23 17:56:19.621427+0800 多请求并发[12865:1232111] 请求3、4发出去了:<NSThread: 0x600003c950c0>{number = 3, name = (null)}
2018-10-23 17:56:19.628091+0800 多请求并发[12865:1232112] 请求1发出去了:<NSThread: 0x600003c91f80>{number = 5, name = (null)}
2018-10-23 17:56:19.628295+0800 多请求并发[12865:1232112] 请求2,signalStr:11 == <NSThread: 0x600003c91f80>{number = 5, name = (null)}
2018-10-23 17:56:19.629137+0800 多请求并发[12865:1232112] 这里发完请求2了
2018-10-23 17:56:19.761764+0800 多请求并发[12865:1232112] 请求1的回调结果:<NSThread: 0x600003c91f80>{number = 5, name = (null)}
2018-10-23 17:56:19.763890+0800 多请求并发[12865:1232111] 被请求3或请求4的回调结果:<NSThread: 0x600003c950c0>{number = 3, name = (null)}
2018-10-23 17:56:19.764948+0800 多请求并发[12865:1232111] 被请求3或请求4的回调结果:<NSThread: 0x600003c950c0>{number = 3, name = (null)}
2018-10-23 17:56:19.765974+0800 多请求并发[12865:1232111] 请求2的结果:22 == <NSThread: 0x600003c950c0>{number = 3, name = (null)}

显然,请求2在请求1回调前发出了,不符合我们的预期。

分析问题:因为任务2即请求2依赖的是请求1的回调结果,而不是请求1,所以即使是把请求1、2放在串行队列异步执行(即开辟一条子线程,按顺序执行)依旧达不到我们想要的效果;这里要用到信号量来控制线程同步,才能达到我们预期的效果。

正确代码:

代码2如下:(请求1、2放在串行队列异步,用信号量的方式实现请求2与请求1回调数据按顺序执行)也可见实例代码requestFourPicTestThreeRightSync方法

{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_queue_t syncQueue = dispatch_queue_create("ayncQueue", DISPATCH_QUEUE_SERIAL);
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_async(queue, ^{
        {//请求1
            dispatch_async(syncQueue, ^{
                //请求1
                NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                    UIImage *image = [UIImage imageWithData:data];
                    NSLog(@"请求1的回调结果:%@",[NSThread currentThread]);
                    self.signalStr = @"22";
                     dispatch_semaphore_signal(semaphore);
                }];
                [task resume];
                NSLog(@"请求1发出去了:%@",[NSThread currentThread]);
                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            });
            ///请求2
            dispatch_async(syncQueue, ^{
                //请求2
                    NSLog(@"请求2,signalStr:%@ == %@",self.signalStr,[NSThread currentThread]);
                    NSURLSessionDataTask *taskW = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                        UIImage *image = [UIImage imageWithData:data];
                        NSLog(@"请求2的结果:%@ == %@",self.signalStr,[NSThread currentThread]);
                        dispatch_semaphore_signal(semaphore);
                    }];
                    [taskW resume];
                    NSLog(@"这里发完请求2了");
                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            });
        }
    });
    //请求3,4
    for (NSInteger index = 0; index < 2; index ++) {
        dispatch_async(queue, ^{
            NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                UIImage *image = [UIImage imageWithData:data];
                NSLog(@"被请求3或请求4的回调结果:%@",[NSThread currentThread]);
            }];
            [task resume];
            NSLog(@"请求3、4发出去了:%@",[NSThread currentThread]);
        });
    }
}

打印:

2018-10-24 14:24:02.633241+0800 多请求并发[15934:1574963] 请求3、4发出去了:<NSThread: 0x600002d90ec0>{number = 5, name = (null)}
2018-10-24 14:24:02.633313+0800 多请求并发[15934:1574965] 请求3、4发出去了:<NSThread: 0x600002d90b40>{number = 3, name = (null)}
2018-10-24 14:24:02.633344+0800 多请求并发[15934:1574964] 请求1发出去了:<NSThread: 0x600002d90dc0>{number = 4, name = (null)}
2018-10-24 14:24:02.718505+0800 多请求并发[15934:1574965] 请求1的回调结果:<NSThread: 0x600002d90b40>{number = 3, name = (null)}
2018-10-24 14:24:02.718846+0800 多请求并发[15934:1574964] 请求2,signalStr:22 == <NSThread: 0x600002d90dc0>{number = 4, name = (null)}
2018-10-24 14:24:02.719216+0800 多请求并发[15934:1574964] 这里发完请求2了
2018-10-24 14:24:02.719791+0800 多请求并发[15934:1574963] 被请求3或请求4的回调结果:<NSThread: 0x600002d90ec0>{number = 5, name = (null)}
2018-10-24 14:24:02.720539+0800 多请求并发[15934:1574965] 被请求3或请求4的回调结果:<NSThread: 0x600002d90b40>{number = 3, name = (null)}
2018-10-24 14:24:02.721175+0800 多请求并发[15934:1574963] 请求2的结果:22 == <NSThread: 0x600002d90ec0>{number = 5, name = (null)}

分析:以上是把请求1、2放在串行队列,下边代码请求是放在并行队列异步执行,打印发现和串行队列效果相同,因为请求1、2的wait是按顺序执行的(如果两个wait分别放在不同线程,则就不会实现信号量实现线程同步的效果了)

代码3如下:(请求1、2放在全局队列异步执行,用信号量的方式实现请求2与请求1回调数据按顺序执行)也可见实例代码:requestFourPicTestThree方法

{//不同线程间同步
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_async(queue, ^{
        {//请求1
            dispatch_async(queue, ^{
                NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                    UIImage *image = [UIImage imageWithData:data];
                    //            NSLog(@"被请求2依赖的请求1的请求回调结果");
                    NSLog(@"请求1的回调结果:%@",[NSThread currentThread]);
                    self.signalStr = @"22";
dispatch_semaphore_signal(semaphore);//要实现同步,这句一定要写在回调最后一行
                }];
                [task resume];
                NSLog(@"请求1发出去了:%@",[NSThread currentThread]);
            });
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        }
        {//请求2
            dispatch_async(queue, ^{
                NSLog(@"请求2,signalStr:%@ == %@",self.signalStr,[NSThread currentThread]);
                NSURLSessionDataTask *taskW = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                    UIImage *image = [UIImage imageWithData:data];
                    NSLog(@"请求2的结果:%@ == %@",self.signalStr,[NSThread currentThread]);
 dispatch_semaphore_signal(semaphore);
                }];
                [taskW resume];
                NSLog(@"这里发完请求2了");
            });
 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        }
    });
    //请求3,4
    for (NSInteger index = 0; index < 2; index ++) {
        dispatch_async(queue, ^{
            NSLog(@"请求3、4发出去了:%@",[NSThread currentThread]);
            NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                UIImage *image = [UIImage imageWithData:data];
                NSLog(@"被请求3或请求4的回调结果:%@",[NSThread currentThread]);
            }];
            [task resume];
        });
    }
}

代码3打印:

{//异步
//            2018-10-24 09:28:38.487954+0800 多请求并发[13432:1268530] 请求3、4发出去了:<NSThread: 0x600002d7aa80>{number = 3, name = (null)}
//            2018-10-24 09:28:38.488392+0800 多请求并发[13432:1268534] 请求3、4发出去了:<NSThread: 0x600002d7b500>{number = 4, name = (null)}
//            2018-10-24 09:28:38.490872+0800 多请求并发[13432:1268527] 请求1发出去了:<NSThread: 0x600002d7cc00>{number = 5, name = (null)}
//            2018-10-24 09:28:38.564867+0800 多请求并发[13432:1268530] 被请求3或请求4的回调结果:<NSThread: 0x600002d7aa80>{number = 3, name = (null)}
//            2018-10-24 09:28:38.565833+0800 多请求并发[13432:1268530] 被请求3或请求4的回调结果:<NSThread: 0x600002d7aa80>{number = 3, name = (null)}
//            2018-10-24 09:28:38.566746+0800 多请求并发[13432:1268530] 请求1的回调结果:<NSThread: 0x600002d7aa80>{number = 3, name = (null)}
//            2018-10-24 09:28:38.567047+0800 多请求并发[13432:1268529] 请求2,signalStr:22 == <NSThread: 0x600002d75340>{number = 6, name = (null)}
//            2018-10-24 09:28:38.567651+0800 多请求并发[13432:1268529] 这里发完请求2了
//            2018-10-24 09:28:38.569846+0800 多请求并发[13432:1268529] 请求2的结果:22 == <NSThread: 0x600002d75340>{number = 6, name = (null)}
//
//        }

代码3和代码2效果一样,都能达到预期效果(发请求2的时候,signalStr都是22,说明发请求2的时候可以拿到请求1的回调结果做参数),都能实现同步的效果,但代码2是两个任务(请求1、2)共用一条线程实现的同步,而代码3开辟了两条线程执行两个任务(请求1、2)实现线程同步,而开线程会消耗内存,所以相比直线代码2的效果更好;注意一点:dispatch_semaphore_signal(semaphore);一定要放在任务块的最后一行,保证任务块回调的所有代码执行完毕,再往下执行,不然会有问题的

4、进某页面要发四个请求,其中某个请求的两个请求参数是另两个请求结果分别返回的两个字段(请求3依赖请求1、2的回调结果)

   分析:请求3依赖1、2的回调,所以3必须在1、2回调结果后发出要用到group,为实现最大效率,请求1、2要异步执行;为最大效率而请求4要和请求1、2异步执行。

代码如下:也可见示例代码requestFourPicTestFour方法

{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_t group = dispatch_group_create();
    
 dispatch_async(queue, ^{
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"请求1发出去了");
        NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            UIImage *image = [UIImage imageWithData:data];
            dispatch_group_leave(group);
            NSLog(@"请求1返回了");
        }];
        [task resume];
    });
   
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"请求2发出去了");
        NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            UIImage *image = [UIImage imageWithData:data];
            dispatch_group_leave(group);
            NSLog(@"请求2返回了");
        }];
        [task resume];
    });
  
    dispatch_group_notify(group, queue, ^{
       
        dispatch_async(queue, ^{
             NSLog(@"请求3发出去了");
            NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                UIImage *image = [UIImage imageWithData:data];
                 NSLog(@"请求3返回了");
            }];
            [task resume];
        });
    });
  });
    dispatch_async(queue, ^{
        NSLog(@"请求4发出去了");
        NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            UIImage *image = [UIImage imageWithData:data];
            NSLog(@"请求4返回了");
        }];
        [task resume];
    });
}

打印如下:

2018-10-24 10:04:30.291364+0800 多请求并发[13696:1306330] 请求2发出去了
2018-10-24 10:04:30.291364+0800 多请求并发[13696:1306331] 请求1发出去了
2018-10-24 10:04:30.291364+0800 多请求并发[13696:1306335] 请求4发出去了
2018-10-24 10:04:30.374136+0800 多请求并发[13696:1306330] 请求4返回了
2018-10-24 10:04:30.375240+0800 多请求并发[13696:1306332] 请求1返回了
2018-10-24 10:04:30.375869+0800 多请求并发[13696:1306330] 请求2返回了
2018-10-24 10:04:30.375892+0800 多请求并发[13696:1306331] 请求3发出去了
2018-10-24 10:04:30.377663+0800 多请求并发[13696:1306331] 请求3返回了
分析:请求1、2、4同时发出,请求1、2结果回来,3再发出

5、进某页面要发四个请求,请求3依赖请求2的回调结果,请求2依赖于请求1的回调结果

 分析:请求1、2、3要同步执行用信号量保证线程同步,请求1、2、3可放在并行队列异步执行,也可放在串行队列同步执行(和上边的3的情况差不多),为保证效率请求4要和请求1异步并发。

 代码如下:

代码1:(串行队列同步执行,用信号量保证请求回调和其他请求之间同步)见示例代码 requestFourPicTestFiveSync 方法

{//请求1、2、3放在串行队列,用信号量保证同步
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
 dispatch_queue_t syncQueue = dispatch_queue_create("syncQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            UIImage *image = [UIImage imageWithData:data];
            NSLog(@"请求4返回了");            
        }];
        [task resume];
        NSLog(@"请求4发出了:%@",[NSThread currentThread]);
    });
syncQueue, ^{
        {//请求1
        NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            UIImage *image = [UIImage imageWithData:data];
            NSLog(@"请求1返回了:%@",self.signalStr);
            self.signalStr = @"1";
 dispatch_semaphore_signal(semaphore);
        }];
        [task resume];
        NSLog(@"请求1发出了:%@",[NSThread currentThread]);
 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        }
        {//请求2
            NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                UIImage *image = [UIImage imageWithData:data];
                NSLog(@"请求2返回了:%@",self.signalStr);
                self.signalStr = @"2";
dispatch_semaphore_signal(semaphore);
            }];
            [task resume];
            NSLog(@"请求2发出了:%@ == %@",[NSThread currentThread],self.signalStr);
 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        }
        {//请求3
            NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                UIImage *image = [UIImage imageWithData:data];
                NSLog(@"请求3返回了:%@",self.signalStr);
                self.signalStr = @"3";
dispatch_semaphore_signal(semaphore);
            }];
            [task resume];
            NSLog(@"请求3发出了:%@ == %@",[NSThread currentThread],self.signalStr);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        }
    });
}
代码2:(请求1、2、3放在全局队列异步执行,用信号量保证同步)也可见示例代码 requestFourPicTestFiveAsync 方法
{//请求1、2、3放在并行队列,异步执行,用信号量保证同步执行
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            UIImage *image = [UIImage imageWithData:data];
            NSLog(@"请求4返回了");
 
        }];
        [task resume];
        NSLog(@"请求4发出了:%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            UIImage *image = [UIImage imageWithData:data];
            NSLog(@"请求1返回了:%@",self.signalStr);
            self.signalStr = @"1";
             dispatch_semaphore_signal(semaphore);
        }];
        [task resume];
        NSLog(@"请求1发出了:%@",[NSThread currentThread]);
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    /
    dispatch_async(queue, ^{
        NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            UIImage *image = [UIImage imageWithData:data];
            NSLog(@"请求2返回了:%@",self.signalStr);
             self.signalStr = @"2";
             dispatch_semaphore_signal(semaphore);
        }];
        [task resume];
        NSLog(@"请求2发出了:%@",[NSThread currentThread]);
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    dispatch_async(queue, ^{
        NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            UIImage *image = [UIImage imageWithData:data];
            NSLog(@"请求3返回了:%@",self.signalStr);
             self.signalStr = @"3";
             dispatch_semaphore_signal(semaphore);
        }];
        [task resume];
        NSLog(@"请求3发出了:%@",[NSThread currentThread]);
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}

分析:和上边的情况3一样,全局队列异步和串行队列同步都能实现预期效果,但最优解还是同步,与上边情况3同理,全局队列异步执行需要多开线程,占用内存,而且因为要实现同步执行所以不同线程间要来回切换,所以建议用串行同步的方法,可下载示例demo自行运行,查看打印。

6、进某页面要发100个请求

分析:发100个请求,为实现最大效率,能开几条线程就尽量开几条,但是每条线程要占用内存,所以任意开太多线程反而影响执行效率,甚至造成卡顿。所以在此用信号量来控制同时执行的线程数,而gcd是可以自动管理线程,所以只要控制同时执行的线程数量,就相当于限制开几条线程。一般最大允许量是开5条。

代码:也可见示例代码  requestOneHundredPicTestSix 方法

{//限定同时执行的线程数
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(5);
    for (NSInteger index = 0; index < 100; index ++) {
        dispatch_async(queue, ^{
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            NSLog(@"=== %ld",index);
            /
            {
            NSURL *url = [NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"];
            NSURLSession *session = [NSURLSession sharedSession];
          NSURLSessionDataTask * task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                UIImage *iamge = [UIImage imageWithData:data];
            }];
            [task resume];
            }
            /
            NSLog(@"===|||| %ld",index);
            dispatch_semaphore_signal(semaphore);
            NSLog(@"===||||==== %ld",index);
        });
    }
}

以上是常用的gcd的情况,如有其它情况会继续补充。