iOS GCD group 多请求异步 semaphore 多请求同步

在做项目的时候往往会出现多图上传的功能,而恰巧服务器可能只支持单张上传,所以你要遍历请求,而全部上传完成后可能还要刷新列表啊或者给个提示框啊等需求。
有些人可能会一个网络请求成功回调里面再嵌套一个,类推,如果上传9张图就要嵌套9次,很显然这样的代码看上去有点low而且非并发耗时比较慢,推荐使用gcd group 组。话不多说上代码:

//创建一个组
dispatch_group_t group = dispatch_group_create();
for (int i = 0; i <9; I++)
{//模仿多个网络请求
    dispatch_group_async(group,dispatch_get_global_queue(0, 0), ^{
        //异步网络请求
        
        int x = arc4random() % 5;
        //模拟网络请求快慢不确定的情况
        sleep(x);
        
        NSLog(@"group 请求成功OR请求失败 %d!",i);
    });
}
NSLog(@"group开始 网络请求!");

dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    //网络请求完毕 回到主线程更新UI 或者做些其它的操作
    NSLog(@"group所有请求完毕!!!");
});

使用dispatch_group_async函数将多个任务关联到一个Dispatch Group和相应的queue中,group会并发地同时执行这些任务。而且Dispatch Group可以用来阻塞一个线程, 直到group关联的所有的任务完成执行调用dispatch_group_notify方法,这样就达到了想要的效果。

ABF94C9D-3542-4C6C-A30C-2BA6DCDDB02B.png

当然你也可以不使用dispatch_group_async函数,转而使用dispatch_group_enter和dispatch_group_leave,注意这里要配套使用哦。
dispatch_group_enter:通知group,下面的任务马上要放到group中执行了。
dispatch_group_leave:通知group,任务完成了,该任务要从group中移除了。

//创建一个组
dispatch_group_t group = dispatch_group_create();
for (int i = 0; i <9; I++)
{//模仿多个网络请求
    
    dispatch_group_enter(group);
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //异步网络请求
        
        int x = arc4random() % 5;
        //模拟网络请求快慢不确定的情况
        sleep(x);
        NSLog(@"group 请求成功OR请求失败 %d!",i);
        
        dispatch_group_leave(group);
    });
}
NSLog(@"group开始 网络请求!");

dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    //网络请求完毕 回到主线程更新UI 或者做些其它的操作
    NSLog(@"group所有请求完毕!!!");
});
A27BFDF3-170D-40D9-BD7F-3802FAF82D56.png

还有一种情况,比如要做一个相册功能,也是多图上传,但是要有规律按顺序上传。这里就推荐使用dispatch_semaphore_t 信号量,也是利用线程阻塞来实现。直接上代码:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    /// 创建一个线程"001" 确保之后不要阻塞主线程
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        /// 创建一个信号量 数值为1  信号量可以让线程阻塞等待
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
        for (int i = 0; i<9; i++) {
            /// 模仿9个请求任务
            /// 执行dispatch_semaphore_wait 信号量数值 -1.
            /// 当i为0此时的信号量数值为0, 当此时的信号量大于等于0继续执行wait函数下面的语句.
            /// 当i为1此时的信号量数值为-1, 阻塞当前线程 阻塞时长为DISPATCH_TIME_FOREVER, 不执行wait函数下面的语句.
            /// 只有等到执行i为0 的 dispatch_semaphore_signal 方法执行, 信号量数值+1 为0, 唤醒 继续执行wait函数下面的语句.
            /// 以此类推循环.
            NSLog(@"当前线程:%@",[NSThread currentThread]);
        
            /// ******这是一个网络请求开始******
            dispatch_async(dispatch_get_global_queue(0, 0), ^{
                /// 模拟异步网络请求
                int x = arc4random() % 2;
                /// 模拟网络请求快慢
                sleep(x);
                NSLog(@"执行任务代号:%d",i);
                /// 任务结束 信号量数值+1 解放线程"001" 阻塞
                dispatch_semaphore_signal(semaphore);
            });
            /// ******这是一个网络请求结束******

            /// 信号量减1 变为负数 当前线程"001" 阻塞
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        }
    });
}
image.png

如果需要两者结合使用呢也是可以的,这样即能按顺序上传,又能在上传后收到通知做一些提示或者其它操作,请看代码:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    /// 创建一个线程"001" 确保之后不要阻塞主线程
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
    
        dispatch_group_t group = dispatch_group_create();
    
        /// 创建一个信号量 数值为0
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        for (int i = 0; i<9; i++)
        {
            /// 模仿9个请求任务
            dispatch_group_async(group,dispatch_get_global_queue(0, 0), ^{
//                /// 异步网络请求
//                int x = arc4random() % 2;
//                /// 模拟网络请求快慢不确定的情况
//                sleep(x);

                NSLog(@"执行任务:%d 线程:%@",i,[NSThread currentThread]);
                /// 任务结束 信号量数值+1 解放线程"001" 阻塞
                dispatch_semaphore_signal(semaphore);
            });
        
            /// 信号量减1 变为负数 当前线程"001" 阻塞
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            //NSLog(@"阻塞线程:%@",[NSThread currentThread]);
        }
    
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            /// 网络请求完毕 回到主线程更新UI 或者做些其它的操作
            NSLog(@"所有任务执行完毕!!!");
        });
    });
}
image.png

想要顺序(同步)执行异步任务的话,可以把一个个异步任务放在串行队列里面去执行,代码如下:

dispatch_queue_t queue = dispatch_queue_create("serial",DISPATCH_QUEUE_SERIAL);
///在串行队列中 执行第一个异步任务
dispatch_async(queue, ^{
    NSLog(@"1---%@", [NSThread currentThread]);
    [NSThread sleepForTimeInterval:5];
    NSLog(@"xxxxxxxxxxxxxx");
});
///在串行队列中 执行第二个异步任务
dispatch_async(queue, ^{
    NSLog(@"2---%@", [NSThread currentThread]);
});
///在串行队列中 执行第三个异步任务
dispatch_async(queue, ^{
    NSLog(@"3---%@", [NSThread currentThread]);
});
E3F126184247B6AF82003F339439F266.jpg

如果有不同见解欢迎讨论,有错误还请指出,博主加以改正,谢谢!
转载请说明出处,代码在这里。请不要吝啬您的star

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • iOS 多线程系列 -- 基础概述iOS 多线程系列 -- pthreadiOS 多线程系列 -- NSThrea...
    shannoon阅读 4,447评论 0 2
  • 目录:iOS多线程(一)--pthread、NSThreadiOS多线程(二)--GCD详解iOS多线程(三)--...
    Claire_wu阅读 4,733评论 0 6
  • 一、简单介绍下将会用到的一些东西 英语不好就不翻译官方文档了.. 1、dispatch_group_async S...
    Albert新荣阅读 5,719评论 0 1
  • GCD笔记 总结一下多线程部分,最强大的无疑是GCD,那么先从这一块部分讲起. Dispatch Queue的种类...
    jins_1990阅读 4,160评论 0 1
  • GCD (Grand Central Dispatch) :iOS4 开始引入,使用更加方便,程序员只需要将任务添...
    池鹏程阅读 5,199评论 0 2

友情链接更多精彩内容