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

【C/C++】RPC与线程间通信:高效设计的关键选择

文章目录

  • RPC与线程间通信:高效设计的关键选择
    • 1 RPC 的核心用途
    • 2 线程间通信的常规方法
    • 3 RPC 用于线程间通信的潜在意义
    • 4 主要缺点与限制
      • 4.1 缺点列表
      • 4.2 展开
    • 5 替代方案
    • 6 结论

RPC与线程间通信:高效设计的关键选择

在C++或分布式系统设计中,RPC(远程过程调用)通常用于跨进程或跨网络的通信,而线程间通信(在同一进程内)通常采用更高效的机制。


1 RPC 的核心用途

  • 设计目标:隐藏网络通信细节,实现跨进程/跨机器的透明函数调用。
  • 典型场景:微服务、分布式系统、跨语言调用等。

2 线程间通信的常规方法

线程间通信通常依赖以下高效机制:

  • 共享内存:直接访问同一内存区域(需同步机制如互斥锁、原子操作)。
  • 消息队列:通过生产者-消费者模型传递数据(如C++的std::queue + 条件变量)。
  • 管道/信号量:操作系统提供的轻量级通信方式。
  • Future/Promise:异步编程模型(如std::future)。

这些方法的性能开销极低,适合高并发场景。


3 RPC 用于线程间通信的潜在意义

  • 适用场景
    • 统一通信模型:若系统已广泛使用RPC框架(如gRPC、Thrift),且希望保持代码一致性,可在线程间复用同一套接口。
    • 模块解耦:通过RPC接口明确定义线程间交互协议,提升模块独立性(如微内核架构)。
    • 跨语言支持:若线程需调用不同语言编写的模块(如Python/C++混合编程),RPC可提供标准化通信。
    • 调试与监控:RPC框架通常自带日志、跟踪功能,便于分析线程间调用链路。

4 主要缺点与限制

4.1 缺点列表

  • 性能损失:RPC的序列化、协议解析、上下文切换开销远高于共享内存或消息队列。
  • 复杂性增加:需引入RPC框架(如生成桩代码、管理通信协议),提升系统维护成本。
  • 设计过度:若仅为同一进程内通信,RPC属于“杀鸡用牛刀”,可能违背KISS原则。

4.2 展开

RPC的通信开销显著高于共享内存或消息队列,核心原因在于其通信机制的设计目标不同。

  1. 序列化开销
  • RPC 的序列化流程
    • 数据转换:将内存中的数据结构(如对象、结构体)转换为字节流(二进制或文本格式)。
      • 需要处理复杂类型(嵌套对象、动态数组)。
      • 需要处理字节序(Big-Endian vs Little-Endian)。
      • 需要生成元数据描述结构(如Protobuf的字段编号)。
  • 兼容性处理:支持跨语言、版本兼容性(如新增字段不影响旧版本解析)。
  • 数据压缩(可选):减少网络传输量,但增加CPU开销。

示例(以Protobuf为例):

// 原始对象
Person person;
person.set_name("Alice");
person.set_id(123);// 序列化为字节流
std::string buffer;
person.SerializeToString(&buffer);// 开销来源:类型检查、字段编码、内存分配、数据拷贝
  • 共享内存/消息队列的序列化
    • 共享内存
      直接通过指针读写内存,无需序列化

      // 直接写入共享内存
      struct Data { int id; char name[32]; };
      Data* shared_data = (Data*)shm_ptr;
      shared_data->id = 123;
      strcpy(shared_data->name, "Alice");
      
    • 消息队列
      通常传递简单类型(如字符串、二进制块),若需传递复杂对象,可自定义轻量序列化(如内存拷贝)。

    • 关键差异
      RPC的序列化需要通用性(跨语言、跨版本),而共享内存/消息队列通常直接操作内存二进制布局,省去转换步骤。

  1. 协议解析开销
  • RPC 的协议解析流程
    • 协议头解析:提取元数据(如请求ID、方法名、超时时间)。
      • 例如,gRPC基于HTTP/2协议,需要解析复杂的头部帧。
    • 数据反序列化:将字节流还原为内存对象。
      • 需要校验数据完整性(如CRC校验)。
      • 需要处理字段缺失、版本不匹配等异常。
    • 路由处理:根据方法名找到对应的服务实现。

示例(gRPC协议解析):

HTTP/2 Frame Header (9 bytes)
┌───────────────────────────────────────────────┐
│ Length (3B) │ Type (1B) │ Flags (1B) │ Stream ID (4B) │
└───────────────────────────────────────────────┘
gRPC Data Frame (Protobuf Payload)
┌───────────────────────┐
│ Compressed Flag (1B)  │
├───────────────────────┤
│ Message Length (4B)   │
├───────────────────────┤
│ Protobuf Serialized Data │
└───────────────────────┘# 开销来源:逐层解析协议头、校验数据、内存分配
  • 共享内存/消息队列的协议解析
    • 共享内存:无协议,直接访问内存地址。

    • 消息队列:通常使用简单协议(如固定长度的头部 + 负载)。

      struct Message {uint32_t msg_type;  // 4字节消息类型uint32_t data_len;  // 4字节数据长度char data[];        // 可变长度数据
      };
      
    • 关键差异
      RPC需要支持网络传输的可靠性(如重试、流量控制),协议层更复杂;共享内存/消息队列的协议设计更简单,甚至无协议。

  1. 上下文切换(Context Switching)开销
  • RPC 的上下文切换

    • 用户态 ↔ 内核态切换

      • RPC通常基于Socket通信(如TCP/HTTP),每次发送/接收数据需通过内核协议栈。
      • 系统调用(如send(), recv())触发上下文切换。
    • 线程/进程切换

      • 服务端通常使用多线程/协程处理并发请求。
      • 线程调度(如CPU核心切换)带来缓存失效(Cache Miss)和TLB刷新。
    • 量化开销

      • 一次系统调用 ≈ 100~500 ns
      • 一次线程切换 ≈ 1~10 μs
      • 缓存失效代价 ≈ 10~100 ns(取决于数据量)
  • 共享内存/消息队列的上下文切换

    • 共享内存
      • 无系统调用,完全在用户态操作(如通过互斥锁同步)。
      • 线程间通过原子操作或锁同步,无内核介入。
    • 消息队列
      • 若使用用户态队列(如无锁队列),无上下文切换。
      • 若使用内核态队列(如POSIX消息队列),仍有切换开销,但低于网络协议栈。

关键差异
RPC的通信路径涉及内核网络协议栈,而共享内存/消息队列可完全在用户态实现。


  1. 综合对比(以本地通信为例)
    假设传递一个 1KB 的数据块:
步骤RPC(本地回环)共享内存
序列化1~10 μs(Protobuf)0 μs(直接内存访问)
协议解析1~5 μs(HTTP/2 + Protobuf)0 μs
上下文切换2~5 μs(系统调用+线程切换)0.1~1 μs(用户态锁)
总延迟4~20 μs0.1~1 μs

  1. 其他性能影响因素
  • 数据拷贝次数
    • RPC:至少2次拷贝(用户态→内核态→用户态)。
    • 共享内存:0次拷贝(直接访问)。
  • 同步机制
    • RPC:隐含同步等待响应(阻塞或异步回调)。
    • 共享内存:需显式同步(如信号量、锁)。
  • 网络延迟(跨机器场景):
    • 即使在同一机器上,本地回环(Loopback)仍有协议栈处理延迟(约1~10 μs)。

  1. 优化 RPC 性能的技术
    尽管RPC开销较大,但在需要跨网络或解耦的场景中,可通过以下技术减少开销:
    • 零拷贝序列化
      • 使用 FlatBuffers、Cap’n Proto 等库,直接操作内存布局,避免序列化。
    • 轻量协议
      • 替换HTTP/2为自定义二进制协议(如Thrift Binary Protocol)。
    • 用户态网络协议栈
      • 使用 DPDK、RDMA 绕过内核,减少上下文切换。
    • 批处理与流水线
      • 合并多个RPC请求,减少通信次数。

  1. 小结
    • RPC开销高的本质原因
      通用性设计(跨网络、跨语言)牺牲了性能,引入序列化、协议解析、内核态切换等步骤。

    • 共享内存/消息队列的优势
      直接操作内存或使用简单协议,避免冗余计算和上下文切换。

    • 适用场景

      • RPC:跨进程、跨机器、需解耦的分布式系统。
      • 共享内存/消息队列:高性能、低延迟的线程间通信。
    • 在设计通信机制时,需根据延迟要求、数据复杂度、系统边界权衡选择。


5 替代方案

  • 轻量级RPC:使用更高效的本地通信库(如Cap’n Proto RPC,支持零拷贝)。
  • Actor模型:通过消息传递实现线程/协程间通信(如C++的CAF框架)。
  • 共享内存 + 协议:自定义高效二进制协议(如FlatBuffers),避免序列化开销。

6 结论

  • 不推荐常规使用:线程间通信应优先选择共享内存、消息队列等高效机制。

  • 特定场景适用:若需跨语言支持、接口标准化或复用现有RPC框架,可谨慎使用,但需评估性能影响。

  • 最终建议
    在无跨语言、跨进程需求时,避免使用RPC进行线程间通信。若需类似RPC的调用语义,可选择轻量级库(如基于内存的异步任务队列)或Actor模型,兼顾性能与代码可维护性。

相关文章:

【C/C++】RPC与线程间通信:高效设计的关键选择

文章目录 RPC与线程间通信:高效设计的关键选择1 RPC 的核心用途2 线程间通信的常规方法3 RPC 用于线程间通信的潜在意义4 主要缺点与限制4.1 缺点列表4.2 展开 5 替代方案6 结论 RPC与线程间通信:高效设计的关键选择 在C或分布式系统设计中,…...

跨线程和跨进程通信还有多种方式对比

📊 常见通信机制对比 通信方式跨线程支持跨进程支持同步/异步性能编程复杂度特点与适用场景SendMessage✅✅(同桌面)同步较高(阻塞)低简单窗口通信、控制PostMessage✅✅(同桌面)异步高低通知、事件触发COM/DCOM✅✅同步/异步中中高系统级服务、进程间服务封装Socket✅…...

RT Thread Studio创建软件和硬件RTC工程

MCU型号:STM32F103RET6 一.配置软件模拟RTC 1.生成一个带串口输出的工程文件,新建RT-Thread项目工程文件。 2.查看电路图中的串口输出管脚,根据STMCubeMx软件可知此串口为USART1,选择芯片型号为STM32F103RET6,控制台…...

Oracle EBS AP发票被预付款核算创建会计科目时间超长

背景 由于客户职能部门的水电、通信和物业等等费用统一管理或对接部门报销费,在报销费的时候,用户把所有费用分摊到各个末级部门,形成AP发票行有上千行, 问题症状 1、用户过账时,请求创建会计科目一直执行20多个小时未完成,只能手工强行取消请求。 2、取消请求以后,从后…...

驱动开发硬核特训 · Day 30(下篇): 深入解析 lm48100q I2C 音频编解码器驱动模型(基于 i.MX8MP)

作者:嵌入式Jerry 视频教程请关注 B 站:“嵌入式Jerry” 一、背景与目标 在本篇中,我们围绕 TI 的 lm48100q 音频编解码器 展开,深入讲解其作为 I2C 外设如何集成至 Linux 内核音频子系统(ASoC)&#xff0…...

运维--计划任务

计划任务分为一次性和循环性的计划任务 1.date的用法 date 月日时分年 eg:date 100118222023 date:查看时间和日期、修改时间和日期 获取当前日期:date +%F F:日期 获取当前时间:date +%H:%M:%S H:时 M:分 S:秒 获取周几: date +%w w:周 …...

苍穹外卖心得体会

1 登录认证 技术点:JWT令牌技术(JSON Web Token) JWT(JSON Web Token)是一种令牌技术,主要由三部分组成:Header头部、Payload载荷和Signature签名。Header头部存储令牌的类型(如JW…...

Python爬虫实战:获取jd商城最新5060ti 16g显卡销量排行榜商品数据并做分析,为显卡选购做参考

一、引言 1.1 研究目的 本研究旨在利用 Python 爬虫技术,从京东商城获取 “5060ti 16g” 型号显卡的商品数据,并对这些数据进行深入分析。具体目标包括: 实现京东商城的模拟登录,突破登录验证机制,获取登录后的访问权限。高效稳定地爬取按销量排名前 20 的 “5060ti 16g…...

Fedora升级Google Chrome出现GPG check FAILED问题解决办法

https://dl.google.com/linux/linux_signing_key.pub 的 GPG 公钥(0x7FAC5991)已安装 https://dl.google.com/linux/linux_signing_key.pub 的 GPG 公钥(0xD38B4796)已安装 仓库 "google-chrome" 的 GPG 公钥已安装,但是不适用于此软件包。 请检查此仓库的…...

信息系统监理师第二版教材模拟题第三组(含解析)

信息系统监理师模拟题第三组(30题) 监理基础理论 信息系统工程监理的性质是( ) A. 服务性、独立性、公正性、科学性 B. 强制性、营利性、行政性、技术性 C. 临时性、从属性、随意性、主观性 D. 单一性、封闭性、被动性、保守性答案:A 解析:监理具有服务性、独立性、公正…...

Zcanpro搭配USBCANFD-200U在新能源汽车研发测试中的应用指南(周立功/致远电子)

——国产工具链的崛起与智能汽车测试新范式 引言:新能源汽车测试的国产化突围 随着新能源汽车智能化、网联化程度的提升,研发测试面临三大核心挑战:多协议融合(CAN FD/LIN/以太网)、高实时性数据交互需求、复杂工况下…...

青少年抑郁症患者亚群结构和功能连接耦合的重构

目录 1 研究背景及目的 2 研究方法 2.1 数据来源与参与者 2.1.1 MDD患者: 2.1.2 健康对照组: 2.2 神经影像分析流程 2.2.1 图像采集与预处理: 2.2.2 网络构建: 2.2.3 区域结构-功能耦合(SC-FC耦合&#xff09…...

SQL手工注入(DVWA)

手工SQL注入攻击的标准思路 Low等级 (1)判断是否存在注入 (2)猜解字段个数 (3)确定字段顺序 (4)获取当前数据库 (5)获取当前数据库中的表 &#xff08…...

【大模型系列篇】Qwen3开源全新一代大语言模型来了,深入思考,更快行动

Qwen3开源模型全览 Qwen3是全球最强开源模型(MoEDense) Qwen3 采用混合专家(MoE)架构,总参数量 235B,激活仅需 22B。 Qwen3 预训练数据量达 36T,并在后训练阶段多轮强化学习,将非思…...

第 11 届蓝桥杯 C++ 青少组中 / 高级组省赛 2020 年真题,选择题详细解释

一、选择题 第 2 题 在二维数组按行优先存储的情况下,元素 a[i][j] 前的元素个数计算如下: 1. **前面的完整行**:共有 i 行,每行 n 个元素,总计 i * n 个元素。 2. **当前行的前面元素**:在行内&#x…...

flutter 专题 一百零四 Flutter环境搭建

Flutter简介 Flutter 是Google开发的一个移动跨平台(Android 和 iOS)的开发框架,使用的是 Dart 语言。和 React Native 不同的是,Flutter 框架并不是一个严格意义上的原生应用开发框架。Flutter 的目标是用来创建高性能、高稳定性…...

Android之Button、ImageButton、ChipGroup用法

一 控件名称及UI代码 Button、ImageButton、ChipGroup <?xml version="1.0" encoding="utf-8"?> <androidx.coordinatorlayout.widget.CoordinatorLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app=&qu…...

【AI提示词】二八法则专家

提示说明 精通二八法则&#xff08;帕累托法则&#xff09;的广泛应用&#xff0c;擅长将其应用于商业、管理、个人发展等领域&#xff0c;深入理解其在不同场景中的具体表现和实际意义。 提示词 # Role: 二八法则专家## Profile - language: 中文 - description: 精通二八法…...

玩玩OCR

一、Tesseract: 1.下载windows版&#xff1a; tesseract 2. 安装并记下路径&#xff0c;等会要填 3.保存.py文件 import pytesseract from PIL import Image def ocr_local_image(image_path):try:pytesseract.pytesseract.tesseract_cmd rD:\Programs\Tesseract-OCR\tesse…...

set autotrace报错

报错&#xff1a; SQL> set autotrace traceonly SP2-0618: Cannot find the Session Identifier. Check PLUSTRACE role is enabled SP2-0611: Error enabling STATISTICS report原因分析&#xff1a; 根据上面的错误提示“SP2-0618: Cannot find the Session Identifie…...

C++如何设计和实现缓存(cache)来减少对后端存储的访问压力

随着数据量的激增和用户对低延迟、高吞吐量需求的不断提升,如何减少系统瓶颈、提升响应速度成为了开发者的核心挑战之一。在这一背景下,缓存(cache)作为一种关键的技术手段,逐渐成为解决性能问题的核心策略。缓存的本质是通过存储频繁访问的数据或计算结果,减少对后端存储…...

“Everything“工具 是 Windows 上文件名搜索引擎神奇

01 Everything 和其他搜索引擎有何不同 轻量安装文件。 干净简洁的用户界面。 快速文件索引。 快速搜索。 快速启动。 最小资源使用。 轻量数据库。 实时更新。 官网&#xff1a;https://www.voidtools.com/zh-cn/downloads/ 通过网盘分享的文件&#xff1a;Every…...

TIME_WAIT状态+UDP概念及模拟实现服务器和客户端收发数据

目录 一、TIME_WAIT状态存在的原因 二、TIME_WAIT状态存在的意义 三、TIME_WAIT状态的作用 四、UDP的基本概念 4.1 概念 4.2 特点 五、模拟实现UDP服务器和客户端收发数据 5.1 服务器udpser 5.2 客户端udpcil 一、TIME_WAIT状态存在的原因 1.可靠的终止TCP连接。 2.…...

Rust 学习笔记:关于枚举与模式匹配的练习题

Rust 学习笔记&#xff1a;关于枚举与模式匹配的练习题 Rust 学习笔记&#xff1a;关于枚举与模式匹配的练习题以下程序能否通过编译&#xff1f;若能&#xff0c;输出是什么&#xff1f;考虑这两种表示结果类型的方式&#xff0c;若计算成功&#xff0c;则包含值 T&#xff1b…...

快速了解Go+微服务(概念和一个例子)

更多个人笔记&#xff1a;&#xff08;仅供参考&#xff0c;非盈利&#xff09; gitee&#xff1a; https 文章目录 基本概念grpc和简单demo 基本概念 特点&#xff1a; 单一职责&#xff1a;一个服务用来解决一个业务问题面向服务&#xff1a;一个服务封装并对外提供服务&am…...

一篇撸清 Http,SSE 与 WebSocket

HTTP,SSE 和WebSocket都是网络传输的协议,本篇快速介绍三者的概念和比较。 SSE(Server-Sent Events) 是什么? SSE(Server-Sent Events),服务器发送事件, 是一种基于 HTTP 的轻量级协议,允许服务器主动向客户端(如浏览器)推送实时数据。它设计用于单向通信(服务器到…...

56、【OS】【Nuttx】编码规范解读(四)

背景 接之前 blog 53、【OS】【Nuttx】编码规范解读&#xff08;一&#xff09; 54、【OS】【Nuttx】编码规范解读&#xff08;二&#xff09; 55、【OS】【Nuttx】编码规范解读&#xff08;三&#xff09; 分析了行宽格式&#xff0c;注释要求&#xff0c;花括号风格等&#…...

IOT项目——DIY 气象站

开源项目&#xff1a;ESP32 气象站 作者&#xff1a;GiovanniAggiustatutto 原文链接&#xff1a;原文 开源项目&#xff1a;太阳能 WiFi 气象站 V4.0 作者&#xff1a;opengreenenergy 原文链接&#xff1a;原文 DIY 气象站 简介1-制版2-物料 温度设备塔风向标风速计雨量计框…...

MODSIM选型指南:汽车与航空航天企业如何选择仿真平台

1. 引言 在竞争激烈的汽车与航空航天领域&#xff0c;仿真技术已成为产品研发不可或缺的环节。通过在设计阶段验证概念并优化性能&#xff0c;仿真平台能有效缩短开发周期并降低物理样机制作成本。 MODSIM&#xff08;建模与仿真&#xff09;作为达索系统3DEXPERIENCE平台的核…...

【JavaEE】springMVC返回Http响应

目录 一、返回页面二、Controller和ResponseBody与RestController区别三、返回HTML代码⽚段四、返回JSON五、HttpServletResponse设置状态码六、设置Header6.1 HttpServletResponse设置6.2 RequestMapping设置 一、返回页面 步骤如下&#xff1a; 我们先要在static目录下创建…...