模拟实战-用CompletableFuture优化远程RPC调用

实战场景

 这是广州某500-900人互联网厂的面试原题

手写并发优化解决思路

我们要调用对方的RPC接口,我们的RPC接口每调用一次对方都会阻塞50ms

但是我们的业务要批量调用RPC,例如我们要批量调用1k次,我们不可能在for循环里面写1k次远程调用,因为我们1次就会阻塞50ms,我们for循环弄1k次那么就要等待1k×50ms

我们还要保证返回的结果是按照我们的请求顺序的

场景介绍:我们这边是C端的,我们不可能修改对方的代码,所以我们只能尽可能优化我们自己的代码提高接口效率


解决思路

1.通过Hash算法来分批运算,最后把结果存到map<Integer,String>里面然后来取,因为我们的顺序由id从低到高,所以我们可以通过id在map里面根据顺序取出然后放到我们的List里面

2.我们for循环,然后每一次循环都开启一个异步线程将结果存到Map里面,然后我们最终存到List。但我一开始有个问题,就是我没等全部执行完就存到我们的Map里面了,因为我不会写那个全局等待的代码......破防了

我最终的解决思路是2

package com.kira.scaffoldmvc.appender;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.stream.IntStream;public class RpcBatchRequestTest {static RpcService rpcService = new RpcService();public static void main(String[] args) throws ExecutionException, InterruptedException {// rpc 请求参数List<Integer> requestIds = IntStream.range(0, 1000).boxed().collect(Collectors.toList());// rpc 调用List<String> results = batchGetDetails(requestIds);// 输出for (String result : results) {System.out.println(result);}// 预期输出// details 0// details 1// details 2// .......// details 999}/*** 某个 rpc service 的接口只提供单个调用* 此处需要做一个封装,多次请求后返回** 要求按照顺序返回** @param ids* @return*/public static List<String> batchGetDetails(List<Integer> ids) throws ExecutionException, InterruptedException {
//         单次调用
//         RpcService rpcService = new RpcService();
//         String rpcResult = rpcService.rpcGetDetailsById(1);List<String> list=new ArrayList<>();HashMap<Integer,String> map=new HashMap<>();List<CompletableFuture<Void>> futures = new ArrayList<>();//for循环里面的每一个都开启一个forfor(int i=0;i<ids.size();i++){int finalI = i;CompletableFuture future=CompletableFuture.supplyAsync(() -> {String s = rpcService.rpcGetDetailsById(ids.get(finalI));map.put(finalI, s);return s;});
futures.add(future);}//futures.toArray(new CompletableFuture[0]))      将future数组转成CompletableFuture数组//如果你传入 new CompletableFuture[0],Java 会动态调整数组大小,以适应 futures 中的元素数//addOf()等待所有Completable异步线程都执行完CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();// TODO 在此处实现批量调用for(int i=0;i<ids.size();i++){list.add(map.get(i));}return list;}
}class RpcService {public String rpcGetDetailsById(int id) {// 模拟 rpc service 耗时try {Thread.sleep(50L);} catch (InterruptedException e) {throw new RuntimeException(e);}return "details " + id;}
}

分批推送的解决思路

每批为500份

package com.kira.scaffoldmvc.appender;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.stream.IntStream;public class RpcBatchRequestTest2 {static RpcService rpcService = new RpcService();public static void main(String[] args) throws ExecutionException, InterruptedException {// rpc 请求参数List<Integer> requestIds = IntStream.range(0, 1000).boxed().collect(Collectors.toList());// rpc 调用List<String> results = batchGetDetails(requestIds);// 输出for (String result : results) {System.out.println(result);}}/*** 按批次异步调用 RPC 接口,并确保按顺序返回** @param ids 请求 ID 列表* @return 按顺序返回的结果列表*/public static List<String> batchGetDetails(List<Integer> ids) throws ExecutionException, InterruptedException {int batchSize = 500; // 每批大小List<CompletableFuture<List<String>>> batchFutures = new ArrayList<>();// 按批次切分数据for (int i = 0; i < ids.size(); i += batchSize) {int start = i;int end = Math.min(i + batchSize, ids.size());List<Integer> batch = ids.subList(start, end);// 异步处理每个批次CompletableFuture<List<String>> batchFuture = CompletableFuture.supplyAsync(() -> batch.stream().map(rpcService::rpcGetDetailsById) // 调用 RPC 方法.collect(Collectors.toList()));batchFutures.add(batchFuture);}// 等待所有批次完成并收集结果List<String> results = new ArrayList<>();CompletableFuture.allOf(batchFutures.toArray(new CompletableFuture[0])).join();for (CompletableFuture<List<String>> future : batchFutures) {results.addAll(future.get());}return results;}
}class RpcService2 {public String rpcGetDetailsById(int id) {// 模拟 rpc service 耗时try {Thread.sleep(50L);} catch (InterruptedException e) {throw new RuntimeException(e);}return "details " + id;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/12105.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习10

自定义数据集 使用scikit-learn中svm的包实现svm分类 代码 import numpy as np import matplotlib.pyplot as pltclass1_points np.array([[1.9, 1.2],[1.5, 2.1],[1.9, 0.5],[1.5, 0.9],[0.9, 1.2],[1.1, 1.7],[1.4, 1.1]])class2_points np.array([[3.2, 3.2],[3.7, 2.9],…

股票入门知识

股票入门&#xff08;更适合中国宝宝体制&#xff09; 股市基础知识 本文介绍了股票的基础知识&#xff0c;股票的分类&#xff0c;各板块发行上市条件&#xff0c;股票代码&#xff0c;交易时间&#xff0c;交易规则&#xff0c;炒股术语&#xff0c;影响股价的因素&#xf…

Golang 并发机制-3:通道(channels)机制详解

并发编程是一种创建性能优化且响应迅速的软件的强大方法。Golang&#xff08;也称为 Go&#xff09;通过通道&#xff08;channels&#xff09;这一特性&#xff0c;能够可靠且优雅地实现并发通信。本文将揭示通道的概念&#xff0c;解释其在并发编程中的作用&#xff0c;并提供…

C#,入门教程(11)——枚举(Enum)的基础知识和高级应用

上一篇&#xff1a; C#&#xff0c;入门教程(10)——常量、变量与命名规则的基础知识https://blog.csdn.net/beijinghorn/article/details/123913570 不会枚举&#xff0c;就不会编程&#xff01; 枚举 一个有组织的常量系列 比如&#xff1a;一个星期每一天的名字&#xf…

读书笔记--分布式架构的异步化和缓存技术原理及应用场景

本篇是在上一篇的基础上&#xff0c;主要对分布式应用架构下的异步化机制和缓存技术进行学习&#xff0c;主要记录和思考如下&#xff0c;供大家学习参考。大家知道原来传统的单一WAR应用中&#xff0c;由于所有数据都在同一个数据库中&#xff0c;因此事务问题一般借助数据库事…

【C++】继承(下)

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解C的继承&#xff08;下&#xff09;&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 5.继承与友元6.继承与静态成员7.复杂的菱形继承及菱形虚拟继承8.继…

基于LLM的路由在专家混合应用:一种新颖的交易框架,该框架在夏普比率和总回报方面提升了超过25%

“LLM-Based Routing in Mixture of Experts: A Novel Framework for Trading” 论文地址&#xff1a;https://arxiv.org/pdf/2501.09636 摘要 随着深度学习和大语言模型&#xff08;LLMs&#xff09;的不断进步&#xff0c;混合专家&#xff08;MoE&#xff09;机制在股票投资…

Med-R2:基于循证医学的检索推理框架:提升大语言模型医疗问答能力的新方法

Med-R2 : Crafting Trustworthy LLM Physicians through Retrieval and Reasoning of Evidence-Based Medicine Med-R2框架Why - 这个研究要解决什么现实问题What - 核心发现或论点是什么How - 1. 前人研究的局限性How - 2. 你的创新方法/视角How - 3. 关键数据支持How - 4. 可…

【Blazor学习笔记】.NET Blazor学习笔记

我是大标题 我学习Blazor的顺序是基于Blazor University&#xff0c;然后实际内容不完全基于它&#xff0c;因为它的例子还是基于.NET Core 3.1做的&#xff0c;距离现在很遥远了。 截至本文撰写的时间&#xff0c;2025年&#xff0c;最新的.NET是.NET9了都&#xff0c;可能1…

C++ Primer 迭代器

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

2 [GitHub遭遇严重供应链投毒攻击]

近日&#xff0c;有黑客针对 Discord Top.gg 的GitHub 账户发起了供应链攻击&#xff0c;此次攻击导致账户密码、凭证和其他敏感信息被盗&#xff0c;同时也影响到了大量开发人员。 Checkmarx 在一份技术报告中提到&#xff0c;黑客在这次攻击中使用了多种TTP&#xff0c;其中…

【AudioClassificationModelZoo-Pytorch】基于Pytorch的声音事件检测分类系统

源码&#xff1a;https://github.com/Shybert-AI/AudioClassificationModelZoo-Pytorch 模型测试表 模型网络结构batch_sizeFLOPs(G)Params(M)特征提取方式数据集类别数量模型验证集性能EcapaTdnn1280.486.1melUrbanSound8K10accuracy0.974, precision0.972 recall0.967, F1-s…

基于Spring Security 6的OAuth2 系列之七 - 授权服务器--自定义数据库客户端信息

之所以想写这一系列&#xff0c;是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器&#xff0c;但当时基于spring-boot 2.3.x&#xff0c;其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0&#xff0c;结果一看Spring Security也升级…

Jupyterlab和notebook修改文件的默认存放路径的方法

文章目录 1.缘由2.操作流程2.1找到默认的路径2.2创建配置文件2.3修改配置文件内容2.4注意事项 1.缘由 我自己使用jupyterlab的时候&#xff0c;打开是在这个浏览器上面打开的&#xff0c;但是这个打开的文件路径显示的是C盘上面路径&#xff0c;所以这个就很麻烦&#xff0c;因…

算法题(56):旋转链表

审题&#xff1a; 我们需要根据k的大小把链表向右移动对应次数&#xff0c;并返回移动后的链表的头结点指针 思路&#xff1a; 根据提示中的数据大小我们发现&#xff1a;k的值可以远大于节点数。 也就是说我们对链表的操作存在周期&#xff0c;如果k%len0&#xff0c;说明我们…

新月军事战略分析系统使用手册

新月人物传记&#xff1a; 人物传记之新月篇-CSDN博客 相关故事链接&#xff1a;星际智慧农业系统&#xff08;SAS&#xff09;&#xff0c;智慧农业的未来篇章-CSDN博客 “新月智能武器系统”CIWS&#xff0c;开启智能武器的新纪元-CSDN博客 “新月之智”智能战术头盔系统&…

金山打字游戏2010绿色版,Win7-11可用DxWnd完美运行

金山打字游戏2010绿色版&#xff0c;Win7-11可用DxWnd完美运行 链接&#xff1a;https://pan.xunlei.com/s/VOIAYCzmkbDfdASGJa_uLjquA1?pwd67vw# 进入游戏后&#xff0c;如果输入不了英文字母&#xff08;很可能是中文输入状态&#xff09;&#xff0c;就按一下“Shift”键…

99,[7] buuctf web [羊城杯2020]easyphp

进入靶场 <?php// 使用 scandir 函数扫描当前目录&#xff08;即脚本所在目录&#xff09;下的所有文件和文件夹// 该函数会返回一个包含目录下所有文件和文件夹名称的数组$files scandir(./); // 遍历扫描得到的文件和文件夹名称数组foreach($files as $file) {// 使用 …

Hot100之图论

200岛屿数量 题目 思路解析 把访问过的格子插上棋子 思想是先污染再治理&#xff0c;我们有一个inArea&#xff08;&#xff09;函数&#xff0c;是判断是否出界了 我们先dfs&#xff08;&#xff09;放各个方向遍历&#xff0c;然后我们再把这个位置标为0 我们岛屿是连着…

html中的表格属性以及合并操作

表格用table定义&#xff0c;标签标题用caption标签定义&#xff1b;用tr定义表格的若干行&#xff1b;用td定义若干个单元格&#xff1b;&#xff08;当单元格是表头时&#xff0c;用th标签定义&#xff09;&#xff08;th标签会略粗于td标签&#xff09; table的整体外观取决…