当前位置: 首页 > article >正文

模拟实战-用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;}
}

相关文章:

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

实战场景 这是广州某500-900人互联网厂的面试原题 手写并发优化解决思路 我们要调用对方的RPC接口&#xff0c;我们的RPC接口每调用一次对方都会阻塞50ms 但是我们的业务要批量调用RPC&#xff0c;例如我们要批量调用1k次&#xff0c;我们不可能在for循环里面写1k次远程调用…...

图 、图的存储

图的基本概念&#xff1a; 图g由顶点集v和边集e组成&#xff0c;记为g&#xff08;v&#xff0c;e&#xff09; 用|v|表示图g中顶点的个数&#xff0c;也称图g的阶&#xff0c;用|e|表示图g中边的条数 线性表可以是空表&#xff0c;树可以是空树&#xff0c;但图不可以是空&…...

快速提升网站收录:利用网站新闻发布功能

本文转自&#xff1a;百万收录网 原文链接&#xff1a;https://www.baiwanshoulu.com/63.html 利用网站新闻发布功能快速提升网站收录是一个有效的策略。以下是一些具体的建议&#xff0c;帮助你更好地利用这一功能&#xff1a; 一、保持新闻更新频率 搜索引擎尤其重视网站的…...

信息学奥赛一本通 2112:【24CSPJ普及组】地图探险(explore) | 洛谷 P11228 [CSP-J 2024] 地图探险

【题目链接】 ybt 2112&#xff1a;【24CSPJ普及组】地图探险&#xff08;explore&#xff09; 洛谷 P11228 [CSP-J 2024] 地图探险 【题目考点】 1. 模拟 2. 二维数组 3. 方向数组 在一个矩阵中&#xff0c;当前位置为(sx, sy)&#xff0c;将下一个位置与当前位置横纵坐…...

【数据结构】(4) 线性表 List

一、什么是线性表 线性表就是 n 个相同类型元素的有限序列&#xff0c;每一个元素只有一个前驱和后继&#xff08;除了第一个和最后一个元素&#xff09;。 数据结构中&#xff0c;常见的线性表有&#xff1a;顺序表、链表、栈、队列。 二、什么是 List List 是 Java 中的线性…...

YOLO11/ultralytics:环境搭建

前言 人工智能物体识别行业应该已经饱和了吧&#xff1f;或许现在并不是一个好的入行时候。 最近看到了各种各样相关的扩展应用&#xff0c;为了理解它&#xff0c;我不得不去尝试了解一下。 我选择了git里非常受欢迎的yolo系列&#xff0c;并尝试了最新版本YOLO11或者叫它ultr…...

Spring Boot 2 快速教程:WebFlux优缺点及性能分析(四)

WebFlux优缺点 【来源DeepSeek】 Spring WebFlux 是 Spring 框架提供的响应式编程模型&#xff0c;旨在支持非阻塞、异步和高并发的应用场景。其优缺点如下&#xff1a; 优点 高并发与低资源消耗 非阻塞 I/O&#xff1a;基于事件循环模型&#xff08;如 Netty&#xff09;&am…...

《OpenCV》——图像透视转换

图像透视转换简介 在 OpenCV 里&#xff0c;图像透视转换属于重要的几何变换&#xff0c;也被叫做投影变换。下面从原理、实现步骤、相关函数和应用场景几个方面为你详细介绍。 原理 实现步骤 选取对应点&#xff1a;要在源图像和目标图像上分别找出至少四个对应的点。这些对…...

20250202在Ubuntu22.04下使用Guvcview录像的时候降噪

20250202在Ubuntu22.04下使用Guvcview录像的时候降噪 2025/2/2 21:25 声卡&#xff1a;笔记本电脑的摄像头自带的【USB接口的】麦克风。没有外接3.5mm接口的耳机。 缘起&#xff1a;在安装Ubuntu18.04/20.04系统的笔记本电脑中直接使用Guvcview录像的时候底噪很大&#xff01; …...

fflush的概念和使用案例

fflush() 是C语言标准库中用于控制输入/输出缓冲区的函数&#xff0c;其主要功能是强制刷新缓冲区&#xff0c;确保数据及时写入目标设备&#xff08;如屏幕、文件&#xff09;。以下是其概念和典型使用场景&#xff1a; 概念 功能&#xff1a; 刷新指定流的缓冲区。对于输出流…...

2024年度总结

首先&#xff0c;我是在2023年结束高中生涯进入大学的&#xff0c;难免会有固化的“高中生”思维&#xff0c;我等着老师的安排&#xff0c;看着课表上课&#xff0c;跟着时间吃饭&#xff0c;睡觉&#xff0c;偶尔会熬夜&#xff0c;但整体跟高中没差太多。我对社团没兴趣&…...

The Simulation技术浅析(四):随机数生成

随机数生成技术 是 The Simulation 中的核心组成部分,广泛应用于蒙特卡洛模拟、密码学、统计建模等领域。随机数生成技术主要分为 伪随机数生成器(PRNG,Pseudo-Random Number Generator) 和 真随机数生成器(TRNG,True Random Number Generator)。 1. 伪随机数生成器(PR…...

如何生成强密码:提高网络安全性的全面指南

引言 在数字化时代&#xff0c;密码的安全性至关重要。随着我们在社交媒体、电子邮件、在线银行等平台上储存越来越多的个人信息&#xff0c;强密码的使用变得更加关键。强密码能有效防止暴力破解、字典攻击等安全威胁。因此&#xff0c;在本文中&#xff0c;我们将深入探讨如…...

结构体DMA串口接收比特错位

发送&#xff1a; 显示&#xff1a; uint16_t接收时候会比特错位。...

如何在Intellij IDEA中识别一个文件夹下的多个Maven module?

目录 问题描述 理想情况 手动添加Module&#xff0c;配置Intellij IDEA的Project Structure 问题描述 一个文件夹下有多个Maven项目&#xff0c;一个一个开窗口打开可行但是太麻烦。直接open整个文件夹会发现Intellij IDEA默认可能就识别一个或者几个Maven项目&#xff0c;如…...

基于UKF-IMM无迹卡尔曼滤波与交互式多模型的轨迹跟踪算法matlab仿真,对比EKF-IMM和UKF

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于UKF-IMM无迹卡尔曼滤波与交互式多模型的轨迹跟踪算法matlab仿真,对比EKF-IMM和UKF。 2.测试软件版本以及运行结果展示 MATLAB2022A版本运行 3.核心程序 .…...

YOLOV11-1:YoloV11-安装和CLI方式训练模型

YoloV11-安装和CLI方式训练模型 1.安装和运行1.1安装的基础环境1.2安装yolo相关组件1.3命令行方式使用1.3.1 训练1.3.2 预测 本文介绍yoloV11的安装和命令行接口 1.安装和运行 1.1安装的基础环境 GPU环境&#xff0c;其中CUDA是12.4版本 1.2安装yolo相关组件 # 克隆github…...

用FormLinker实现自动调整数据格式,批量导入微软表单

每天早上打开Excel时&#xff0c;你是否也经历过这样的噩梦&#xff1f; 熬夜调整好的问卷格式&#xff0c;导入微软表单后全乱套 客户发来的PDF反馈表&#xff0c;手动录入3小时才完成10% 200道题库要转为在线测试&#xff0c;复制粘贴到手指抽筋 微软官方数据显示&#xf…...

Pluto固件编译笔记

前段时间我已经做到在电脑上交叉编译一个简单的c/c程序&#xff0c;然后复制到pluto上运行。 要做到这一点&#xff0c;其实参考adi pluto官网的wiki就能做到了。 但这样有几个问题&#xff0c;只能做到简易程序&#xff0c;如果程序复杂&#xff0c;要调用更多库而SYSROOT里…...

Docker Hub 镜像 Pull 失败的解决方案

目录 引言一、问题二、原因三、解决方法四、参考文献 引言 在云原生技术火热的当下&#xff0c;Docker可谓是其基础&#xff0c;由于其简单以及方便性&#xff0c;让开发人员不必再为环境配置问题而伤脑筋&#xff0c;因为可将其看作一个虚拟机程序去理解。所以掌握好它可谓是…...

弄懂Runable,Callable,Future之间的关系

JDK1.5之前&#xff0c;我们创建线程有这样两种方式 1.继承Thread类 2.连接实现Runnable接口 但是这两个方法我们都没有返回值&#xff0c;如果需要获取任务返回结果怎么办&#xff1f; 然后在JDK1.5之后&#xff0c;官方就提供了Callable和Future&#xff0c;有获取任务返…...

Kafka中文文档

文章来源&#xff1a;https://kafka.cadn.net.cn 什么是事件流式处理&#xff1f; 事件流是人体中枢神经系统的数字等价物。它是 为“永远在线”的世界奠定技术基础&#xff0c;在这个世界里&#xff0c;企业越来越多地使用软件定义 和 automated&#xff0c;而软件的用户更…...

Shell $0

个人博客地址&#xff1a;Shell $0 | 一张假钞的真实世界 我们已经知道在Shell中$0表示Shell脚本的文件名&#xff0c;但在有脚本调用的情形中&#xff0c;子脚本中的$0会是什么值呢&#xff1f;我们通过下面的实例来看。 已测试系统列表&#xff1a; Mac OS X EI Capitan 1…...

Hugging Face GGUF 模型可视化

Hugging Face GGUF 模型可视化 1. Finding GGUF files (检索 GGUF 模型)2. Viewer for metadata & tensors info (可视化 GGUF 模型)References 无知小儿&#xff0c;仙家雄霸天下&#xff0c;依附强者才是唯一的出路。否则天地虽大&#xff0c;也让你们无路可走&#xff0…...

使用istio实现权重路由

istio概述 **概述&#xff1a;**Istio 是一个开源的 服务网格&#xff08;Service Mesh&#xff09;解决方案&#xff0c;主要用于管理、保护和监控微服务架构中的服务通信。它为微服务提供了基础设施层的控制功能&#xff0c;不需要更改应用程序的代码&#xff0c;从而解决服…...

小程序项目-购物-首页与准备

前言 这一节讲一个购物项目 1. 项目介绍与项目文档 我们这里可以打开一个网址 https://applet-base-api-t.itheima.net/docs-uni-shop/index.htm 就可以查看对应的文档 2. 配置uni-app的开发环境 可以先打开这个的官网 https://uniapp.dcloud.net.cn/ 使用这个就可以发布到…...

基于 NodeJs 一个后端接口的创建过程及其规范 -- 【elpis全栈项目】

基于 NodeJs 一个后端接口的创建过程及其规范 一个接口的诞生&#xff1a; #mermaid-svg-46HXZKI3fdnO0rKV {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-46HXZKI3fdnO0rKV .error-icon{fill:#552222;}#mermaid-sv…...

【hot100】刷题记录(8)-矩阵置零

题目描述&#xff1a; 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]]示例 2…...

C语言教学第三课:运算符与表达式

一、课程导入 同学们&#xff0c;上节课我们学习了变量和数据类型&#xff0c;这些是C语言的基础。今天&#xff0c;我们将继续深入学习C语言中的运算符与表达式。运算符是C语言中用于执行各种操作的符号&#xff0c;而表达式则是由变量、常量和运算符组成的有意义的组合。通过…...

一文讲解Spring中应用的设计模式

我们都知道Spring 框架中用了蛮多设计模式的&#xff1a; 工厂模式呢&#xff0c;就是用来创建对象的&#xff0c;把对象的创建和使用分开&#xff0c;这样代码更灵活。代理模式呢&#xff0c;是用一个代理对象来控制对真实对象的访问&#xff0c;可以在访问前后做一些处理。单…...