并行处理(并行发送api请求等)

在最近遇见的一个业务中,需要调用某开放平台的api,这个api会返回出一个签署列表,签署列表中包含有一个openUserid的属性,这个openUserid包含了用户的实名认证信息,需要一并返回到前端方便展示。因为开放平台没有提供批量请求的方法,所以只能在这个列表中循环调用api来获取需要的数据。

因为在循环里去请求http地址本身就是非常不可靠的,效率会非常非常的慢,这个接口一度需要五六秒的响应时间。因为不能批量请求,所以有一种优化方式就是并行发送请求去请求api。

思路就是创建线程池和一个计数器,使用线程池来并行执行任务,使用 CountDownLatch 来同步所有任务的完成,最后收集结果并处理。

以下是这个的代码示范

1.创建一个列表长度的线程池和计数器,并且创建一个收集结果的list

//使用ExecutorService方式
ExecutorService executorService = Executors.newFixedThreadPool(signTasks.size());
//计数器
CountDownLatch countDownLatch = new CountDownLatch(signTasks.size());
List<Future<IdentityInfoVO>> infoList = new ArrayList<>();

 这一段代码的作用是遍历 signTasks 列表中的每个任务,并为每个任务提交一个并行执行的任务到线程池中,在 finally 块中调用 countDownLatch.countDown() 方法,以确保无论任务是否成功完成,计数器都能正确减少。

 signTasks.forEach(
              task ->{
                        Future<IdentityInfoVO> identityInfoVO = executorService.submit(() -> {
                            try {
                                FadadaSignTaskDO fadadaSignTask = taskIdToSignTaskMap.get(task.getSignTaskId());
                                return fadadaSignTaskService.getIdentityInfo(fadadaSignTask.getFadadaOpenId());
                            } finally {
                                countDownLatch.countDown();
                            }
                        });
                        infoList.add(identityInfoVO);
                }
            );

3.最后结束后,来收集这些任务的结果,并将结果应用到每个签名任务中

  • 创建一个 HashMap,用于存储用户身份信息,键是 OpenUserId,值是 IdentityInfoVO 对象。
  • 遍历 infoList 列表中的每个 Future<IdentityInfoVO> 对象,调用 future.get() 方法获取并行任务的结果。
  • 如果获取结果时发生 InterruptedException 或 ExecutionException 异常,记录错误日志。
  • 如果成功获取到 IdentityInfoVO 对象,将其存入 infoVOMap 中,键为 identityInfoVO.getOpenUserId()

最后将用户信息设置到签名任务中

  • 遍历 signTasks 列表中的每个签名任务 signTask
  • 根据 signTask.getSignTaskId() 获取对应的 FadadaSignTaskDO 对象。
  • 从 infoVOMap 中获取对应的用户身份信息 IdentityInfoVO 对象,并将其设置到 signTask 中。
 countDownLatch.await();
                //获取并行流结果
                Map<String, IdentityInfoVO> infoVOMap = new HashMap<>();

                for (Future<IdentityInfoVO> future : infoList) {
                    IdentityInfoVO identityInfoVO = null;
                    try {
                        identityInfoVO = future.get();
                    } catch (InterruptedException | ExecutionException e) {
                        log.error("获取用户信息失败",e);
                    }
                    if (identityInfoVO != null){
                        infoVOMap.put(identityInfoVO.getOpenUserId(),identityInfoVO);
                    }
                }

                signTasks.forEach(signTask -> {
                    FadadaSignTaskDO fadadaSignTask = taskIdToSignTaskMap.get(signTask.getSignTaskId());
                    signTask.setUserInfo(infoVOMap.get(fadadaSignTask.getFadadaOpenId()));
                });

最后可这样做的好处就是可以充分利用cpu的,提高处理速度,特别是当任务执行时间较长时,并行处理可以显著减少总的执行时间。并行处理可以提高效率,但实际性能提升受多种因素影响。理论上,如果没有资源竞争和其他开销,性能提升接近任务数量倍数,但实际中往往无法达到理论上的10倍提升。

最后附上完整代码

//并行处理
            //使用ExecutorService方式
            ExecutorService executorService = Executors.newFixedThreadPool(signTasks.size());
            //计数器
            CountDownLatch countDownLatch = new CountDownLatch(signTasks.size());
            List<Future<IdentityInfoVO>> infoList = new ArrayList<>();
            signTasks.forEach(
                task ->{
                        Future<IdentityInfoVO> identityInfoVO = executorService.submit(() -> {
                            try {
                                FadadaSignTaskDO fadadaSignTask = taskIdToSignTaskMap.get(task.getSignTaskId());
                                return fadadaSignTaskService.getIdentityInfo(fadadaSignTask.getFadadaOpenId());
                            } finally {
                                countDownLatch.countDown();
                            }
                        });
                        infoList.add(identityInfoVO);
                }
            );
            try {
                countDownLatch.await();
                //获取并行流结果
                Map<String, IdentityInfoVO> infoVOMap = new HashMap<>();

                for (Future<IdentityInfoVO> future : infoList) {
                    IdentityInfoVO identityInfoVO = null;
                    try {
                        identityInfoVO = future.get();
                    } catch (InterruptedException | ExecutionException e) {
                        log.error("获取用户信息失败",e);
                    }
                    if (identityInfoVO != null){
                        infoVOMap.put(identityInfoVO.getOpenUserId(),identityInfoVO);
                    }
                }

                signTasks.forEach(signTask -> {
                    FadadaSignTaskDO fadadaSignTask = taskIdToSignTaskMap.get(signTask.getSignTaskId());
                    signTask.setUserInfo(infoVOMap.get(fadadaSignTask.getFadadaOpenId()));
                });
            } catch (Exception e) {
                log.error("获取链接失败", e);
            }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值