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

pybind11 导出 C++ map 在 Python 层 get 访问慢的优化方案

pybind11 导出 C++ map 在 Python 层 get 访问慢的优化方案

问题描述

通过 pybind11 导出 C++ 的 std::mapstd::unordered_map,在 Python 代码中频繁使用 get 方法访问 value 时,性能非常低下。其主要原因是:

  • pybind11 的 map 绑定会导致每次访问都跨越 Python/C++ 边界,开销很大。
  • 如果在 Python 层高频访问 C++ map,每次都要进入 C++ 层查找,效率远低于直接用 Python dict。
  • 如果每次都把整个 map 拷贝到 Python(如频繁调用 get_map_as_dict),则会有更大的性能损耗。

解决方案

1. 批量查找,减少跨界调用

设计 C++ 方法,接收一组 key,批量返回对应的 value,减少 Python/C++ 之间的调用次数。

py::dict batch_get(const std::map<std::string, int>& m, const std::vector<std::string>& keys) {py::dict d;for (const auto& key : keys) {auto it = m.find(key);if (it != m.end()) {d[key.c_str()] = it->second;}}return d;
}

pybind11 绑定:

m.def("batch_get", &batch_get);

Python 调用:

keys = ["a", "b", "c"]
result = mod.batch_get(keys)
# result 是 dict,只包含需要的 key

2. 一次性拷贝 map 到 Python,只在 map 不变时用

如果 map 内容不会频繁变化,可以只在初始化时拷贝一次,后续都在 Python 层查找。

3. to_dict 缓存优化

如果 map 很大且只读或低频变更,可以在 C++ 层实现 to_dict 缓存:

  • 第一次调用时将 map 转为 Python dict 并缓存。
  • 后续 map 未变时直接返回缓存,性能极高。
  • map 变更时清空缓存,下次再生成。

示例代码:

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <optional>namespace py = pybind11;class MapWrapper {
public:std::map<std::string, int> m;std::optional<py::dict> cache;py::dict to_dict() {if (cache.has_value()) {return cache.value();}py::dict d;for (const auto& kv : m) {d[kv.first.c_str()] = kv.second;}cache = d;return d;}void insert(const std::string& key, int value) {m[key] = value;cache.reset(); // 数据变了,清空缓存}
};PYBIND11_MODULE(example, m) {py::class_<MapWrapper>(m, "MapWrapper").def(py::init<>()).def("to_dict", &MapWrapper::to_dict).def("insert", &MapWrapper::insert);
}

Python 用法:

w = example.MapWrapper()
w.insert("a", 1)
d = w.to_dict()  # 第一次生成并缓存
d2 = w.to_dict() # 直接返回缓存,速度极快

总结

  • 跨 Python/C++ 边界的高频调用是性能瓶颈,需尽量减少。
  • 推荐批量查找或一次性拷贝到 Python。
  • to_dict 缓存方案适合只读或低频变更场景。
  • map 频繁变更时,建议用 batch_get 等批量查找方法。
http://www.dtcms.com/a/266682.html

相关文章:

  • 区块链技术核心组件及应用架构的全面解析
  • python打卡day59@浙大疏锦行
  • 车载电子电气架构 --- OEM走向开放协同与敏捷迭代
  • 数据结构:队列的顺序存储实现
  • 【Linux 系统】基础IO——Linux中对文件的理解
  • 【深度学习新浪潮】如何使用大模型等技术基于序列预测蛋白质的结构,功能和靶点?
  • 【学习笔记】Lean4基础 ing
  • 邮科千兆8光8电工业级交换机互联网的脉搏
  • 洛谷刷题8
  • 云原生Kubernetes系列 | Ingress和Egress网络策略NetworkPolicy结合案例使用详解
  • 5060Ti安装黑屏问题一解
  • 【WIP】【VLAVLM——InternVL系列】
  • Maven编译和打包插件
  • cd-agent更换cd模型(自用)
  • i18next + 原生JS 双引擎:打造前端多语言系统最佳实践
  • Android 网络请求优化全面指南
  • 韩国小说《素食者》读后感
  • C++--多态
  • 全网唯一/Qt结合ffmpeg实现手机端采集摄像头推流到rtsp或rtmp/可切换前置后置摄像头/指定分辨率帧率
  • 在 Minikube 上部署 Kubernetes Deployment 并解决 ImagePullBackOff 问题
  • WPS中配置MathType教程
  • stm32学到什么程度可以找工作?
  • Java学习第十二部分——idea各种项目简介
  • 电阻温升评估的相关测试总结
  • openlayers 判断geojson文件是否在视口内
  • Android BitmapRegionDecoder 详解
  • Ethernet IP与Profinet共舞:网关驱动绿色工业的智慧脉动
  • <tauri><rust><GUI>使用tauri创建一个文件夹扫描程序
  • 深度学习前置知识全面解析:从机器学习到深度学习的进阶之路
  • 《Java修仙传:从凡胎到码帝》第三章:缩进之劫与函数峰试炼