Pybind11的使用
目录
- 1. 引言
- 1.1 Pybind11 简介
- 1.2 为什么需要 Pybind11
- 2. 使用 Pybind11 进行 C++ 与 Python 交互
- 2.1 基本用法
- 2.2 编译与生成共享库
- 2.2.1 在 Linux 下编译
- 2.2.2 在 macOS 下编译
- 2.2.3 编译选项详解
- 2.3 在 Python 中使用编译后的模块
- 3. 高级用法与注意事项
- 3.1 绑定类和复杂数据结构
- 3.2 与 NumPy 交互
- 3.3 随机数生成器的兼容性问题
- 4. 一些🌰
- 4.1 高性能矩阵运算
- 4.2 图像处理
- 4.3 处理大规模数据
- Ref
1. 引言
在现代软件开发中,Python 以其简洁的语法和丰富的生态系统,成为了数据科学和机器学习领域的首选语言。然而,Python 在执行速度方面并不总是能够满足高性能计算的需求。C++ 则以其卓越的性能和强大的系统级编程能力,常用于性能要求极高的场景。Pybind11 是一个开源工具,旨在简化 C++ 与 Python 之间的交互,使得开发者可以在 Python 中方便地调用 C++ 编写的高性能代码。
1.1 Pybind11 简介
Pybind11 是一个轻量级的头文件库,允许在 C++11 及以上标准下,将 C++ 的函数、类和数据结构绑定到 Python 中。它的设计目标是替代 Boost.Python,但没有后者的编译复杂性和体积。通过 Pybind11,开发者可以:
- 高效地将 C++ 函数和类暴露给 Python:无需复杂的配置,即可在 Python 中调用 C++ 代码。
- 支持现代 C++ 特性:兼容 C++11 及以上标准,支持智能指针、模板、枚举等特性。
- 无缝集成:支持 numpy、Eigen 等常用库的数据类型转换。
1.2 为什么需要 Pybind11
在某些应用场景下,Python 的执行效率可能成为瓶颈,例如:
- 计算密集型任务:如大规模矩阵计算、图像处理、机器学习中的核心算法等。
- 实时系统:需要对性能有严格要求的系统,如高频交易、实时信号处理等。
- 遗留代码复用:已有大量用 C++ 编写的代码库,希望在 Python 项目中直接复用。
使用 Pybind11,可以将性能关键的部分用 C++ 编写,并通过简单的绑定在 Python 中调用,从而兼顾开发效率和运行效率。
2. 使用 Pybind11 进行 C++ 与 Python 交互
2.1 基本用法
Pybind11 的基本用法是通过编写 C++ 代码,将函数或类绑定到 Python 中。以下是一个简单的示例:
// example.cpp
#include <pybind11/pybind11.h>int add(int i, int j) {return i + j;
}PYBIND11_MODULE(example, m) {m.def("add", &add, "A function which adds two numbers");
}
在这个示例中,我们定义了一个简单的 add 函数,并使用 PYBIND11_MODULE 宏将其绑定到 Python 模块 example 中。
2.2 编译与生成共享库
为了在 Python 中使用我们编写的 C++ 模块,需要将其编译为共享库。不同的操作系统下,编译命令略有不同。
2.2.1 在 Linux 下编译
g++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
命令解析:
g++:GNU C++ 编译器。-O3:最高级别的优化,提升运行效率。-Wall:开启所有警告,帮助发现潜在问题。-shared:生成共享库(.so文件)。-std=c++11:使用 C++11 标准。-fPIC:生成与位置无关的代码,适用于共享库。$(python3 -m pybind11 --includes):获取 Pybind11 和 Python 的头文件路径。example.cpp:源文件。-o example$(python3-config --extension-suffix):指定输出文件名,$(python3-config --extension-suffix)获取适当的文件扩展名(如.so)。
2.2.2 在 macOS 下编译
g++ -O3 -Wall -shared -std=c++11 -undefined dynamic_lookup $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
命令解析:
- 与 Linux 下基本相同,区别在于:
-undefined dynamic_lookup:macOS 特有选项,允许在链接时未定义的符号在运行时解析。
2.2.3 编译选项详解
-
-O3优化级别-O3是编译器提供的最高级别优化选项,启用所有优化以提升代码运行效率。然而,需要注意的是,过度优化可能会导致编译时间增加,甚至在某些情况下引入不稳定性。 -
-Wall警告信息-Wall选项开启了编译器的所有常用警告,这有助于在编译阶段发现潜在的代码问题,提高代码质量。 -
-shared生成共享库共享库(Linux 下为
.so文件,macOS 下为.dylib或.so)可以被多个程序同时使用,节省内存和磁盘空间。在 Python 中,扩展模块通常以共享库的形式存在。 -
-std=c++11指定标准指定使用 C++11 标准,使得我们可以在代码中使用现代 C++ 特性,如智能指针、自动类型推导等。
-
-fPIC位置无关代码生成的位置无关代码可以在内存中任意位置加载,适用于共享库的生成。
-
-undefined dynamic_lookup这是 macOS 下的特定选项,允许共享库在编译时不解析未定义的符号,而是在运行时解析。这对于动态语言的扩展模块非常有用。
2.3 在 Python 中使用编译后的模块
编译成功后,会生成一个共享库文件,例如 example.cpython-38-x86_64-linux-gnu.so。在 Python 中,我们可以直接导入并使用:
import exampleresult = example.add(3, 4)
print(result) # 输出 7
3. 高级用法与注意事项
3.1 绑定类和复杂数据结构
除了函数,Pybind11 也支持将 C++ 类绑定到 Python 中。例如:
#include <pybind11/pybind11.h>class Pet {
public:Pet(const std::string &name) : name(name) {}void setName(const std::string &name_) { name = name_; }const std::string &getName() const { return name; }
private:std::string name;
};PYBIND11_MODULE(example, m) {pybind11::class_<Pet>(m, "Pet").def(pybind11::init<const std::string &>()).def("setName", &Pet::setName).def("getName", &Pet::getName);
}
在 Python 中:
import examplepet = example.Pet("Milo")
print(pet.getName()) # 输出 "Milo"
pet.setName("Otis")
print(pet.getName()) # 输出 "Otis"
3.2 与 NumPy 交互
Pybind11 提供了对 NumPy 数组的支持,可以方便地在 C++ 和 Python 之间传递数组。
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>double sum_array(pybind11::array_t<double> input) {auto buf = input.request();double *ptr = (double *) buf.ptr;size_t size = buf.size;double sum = 0;for (size_t idx = 0; idx < size; idx++)sum += ptr[idx];return sum;
}PYBIND11_MODULE(example, m) {m.def("sum_array", &sum_array, "Sum elements of a NumPy array");
}
在 Python 中:
import example
import numpy as nparr = np.array([1.0, 2.0, 3.0])
result = example.sum_array(arr)
print(result) # 输出 6.0
3.3 随机数生成器的兼容性问题
在跨语言使用随机数生成器时,需要注意不同语言和库之间的兼容性问题。例如,C++11 提供了 std::mt19937 随机数生成器,而 NumPy 的 np.random.RandomState 则是 Python 中常用的随机数生成器。
问题描述:
np.random.RandomState与std::mt19937不兼容。这意味着,使用 Pybind11 将 C++ 的随机数生成器暴露给 Python 时,不能直接在 Python 中使用np.random.RandomState来设置 C++ 中生成器的状态。
解决方案:
- 统一随机数生成器:在 C++ 和 Python 中使用相同的随机数生成算法和种子。
- 通过种子传递:让 Python 将种子传递给 C++,在 C++ 中初始化
std::mt19937。 - 避免共享状态:将随机数的生成完全放在 C++ 或 Python 中,避免在两者之间共享生成器状态。
#include <pybind11/pybind11.h>
#include <random>double random_double(int seed) {std::mt19937 gen(seed);std::uniform_real_distribution<> dis(0.0, 1.0);return dis(gen);
}PYBIND11_MODULE(example, m) {m.def("random_double", &random_double, "Generate a random double");
}
在 Python 中:
import exampleseed = 42
value = example.random_double(seed)
print(value)
通过在 Python 中控制种子,可以在 C++ 中生成可重复的随机数。
4. 一些🌰
为了更深入地理解 Pybind11 的使用,我们将结合实际例子,探讨如何在项目中应用 Pybind11。
4.1 高性能矩阵运算
假设我们需要对大型矩阵进行复杂的运算,而 Python 的性能无法满足需求。我们可以使用 C++ 编写核心计算逻辑,并通过 Pybind11 暴露给 Python。
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>pybind11::array_t<double> matrix_add(pybind11::array_t<double> a, pybind11::array_t<double> b) {auto buf_a = a.request(), buf_b = b.request();if (buf_a.size != buf_b.size)throw std::runtime_error("Input shapes must match");double *ptr_a = (double *) buf_a.ptr;double *ptr_b = (double *) buf_b.ptr;pybind11::array_t<double> result(buf_a.size);auto buf_result = result.request();double *ptr_result = (double *) buf_result.ptr;for (size_t idx = 0; idx < buf_a.size; idx++)ptr_result[idx] = ptr_a[idx] + ptr_b[idx];result.resize({buf_a.shape[0], buf_a.shape[1]});return result;
}PYBIND11_MODULE(example, m) {m.def("matrix_add", &matrix_add, "Add two matrices");
}
在 Python 中:
import example
import numpy as npa = np.ones((1000, 1000))
b = np.ones((1000, 1000))result = example.matrix_add(a, b)
print(result)
通过这种方式,我们可以大幅提升矩阵运算的性能。
4.2 图像处理
在图像处理领域,性能也是关键因素。我们可以利用 C++ 的高性能和 OpenCV 等库,加速图像处理任务。
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <opencv2/opencv.hpp>pybind11::array_t<uint8_t> convert_to_grayscale(pybind11::array_t<uint8_t> input) {auto buf = input.request();cv::Mat img(buf.shape[0], buf.shape[1], CV_8UC3, (uint8_t *) buf.ptr);cv::Mat gray;cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);pybind11::array_t<uint8_t> result({buf.shape[0], buf.shape[1]}, gray.data);return result;
}PYBIND11_MODULE(example, m) {m.def("convert_to_grayscale", &convert_to_grayscale, "Convert image to grayscale");
}
在 Python 中:
import example
import cv2
import numpy as npimg = cv2.imread('image.jpg')
gray = example.convert_to_grayscale(img)
cv2.imwrite('gray_image.jpg', gray)
4.3 处理大规模数据
在数据科学中,处理大规模数据时,经常需要优化代码性能。以下是一个计算大数组元素平方和的示例:
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>double sum_of_squares(pybind11::array_t<double> input) {auto buf = input.request();double *ptr = (double *) buf.ptr;size_t size = buf.size;double sum = 0;for (size_t idx = 0; idx < size; idx++)sum += ptr[idx] * ptr[idx];return sum;
}PYBIND11_MODULE(example, m) {m.def("sum_of_squares", &sum_of_squares, "Compute sum of squares");
}
在 Python 中:
import example
import numpy as npdata = np.random.rand(1000000)
result = example.sum_of_squares(data)
print(result)
Ref
[1] https://pybind11.readthedocs.io/en/stable/compiling.html#building-manually
相关文章:
Pybind11的使用
目录 1. 引言1.1 Pybind11 简介1.2 为什么需要 Pybind11 2. 使用 Pybind11 进行 C 与 Python 交互2.1 基本用法2.2 编译与生成共享库2.2.1 在 Linux 下编译2.2.2 在 macOS 下编译2.2.3 编译选项详解 2.3 在 Python 中使用编译后的模块 3. 高级用法与注意事项3.1 绑定类和复杂数…...
鸿蒙-沉浸式pc端失效
咨询描述: 因PC北向窗口涉及沉浸式时,预计发生接口废弃导致不兼容变更,涉及接口setImmersiveModeEnabledState、setWindowLayoutFullSceen 如果应用支持沉浸式(窗口全屏且隐藏状态栏&标题栏&Dock栏)࿰…...
【资料分析】刷题日记1
第一套 第二个是相比2019年的增长率,错找为同比增长率 延申: 当出口和进口相比2019年的增长率相同时,可以用盐水解决 √ 一个假设分配(第二次是1.4取1)加法对比选项 基期倍数: 求A是B的多少倍&#x…...
nodejs+express+vue教辅课程辅助教学系统 43x2u前后端分离项目
目录 技术栈具体实现截图系统设计思路技术可行性nodejs类核心代码部分展示可行性论证研究方法解决的思路Express框架介绍源码获取/联系我 技术栈 该系统将采用B/S结构模式,开发软件有很多种可以用,本次开发用到的软件是vscode,用到的数据库是…...
96-javahashmap底层原理
HashMap是Java集合框架中的一个重要类,底层是基于哈希表实现的。哈希表是一种数据结构,可以通过哈希函数来提高查找、插入和删除操作的效率。 以下是HashMap底层实现的一些关键点: 哈希算法:HashMap使用哈希算法来计算键的哈希值…...
AI逻辑推理入门
参考数据鲸 (linklearner.com) 1. 跑通baseline 报名 申领大模型API 模型服务灵积-API-KEY管理 (aliyun.com) 跑通代码 在anaconda新建名为“LLM”的环境,并安装好相应包后,在jupyter notebook上运行baseline01.ipynb 2. 赛题解读 一般情况下,拿到一个赛题之后,我们需…...
力扣3014.输入单词需要的最少按键次数I
给你一个字符串 word,由 不同 小写英文字母组成。 电话键盘上的按键与 不同 小写英文字母集合相映射,可以通过按压按键来组成单词。例如,按键 2 对应 ["a","b","c"],我们需要按一次键来输入 "…...
【Git】远程仓库
本博客的环境是 Ubuntu/Linux 文章目录 集中式与分布式的区别远程仓库新建远程仓库克隆远程仓库向远程仓库推送从远程仓库拉取 配置Git忽略指定文件给命令配置别名 标签管理创建标签操作标签 多人协作本地分支与远程分支连接场景一场景二 集中式与分布式的区别 引荐自关于Git这…...
苹果手机铃声怎么设置自己的歌?3个方法自定义手机铃声
苹果手机内部的手机铃声库只有固定的几首铃声,且都是纯音乐,比较单调,并不是所有用户都喜欢这些铃声。那么,苹果手机铃声怎么设置自己的歌呢?小编这里有3个方法,可以教大家如何将手机铃声设置成自己喜欢的歌…...
828华为云征文|华为Flexus云服务器搭建Cloudreve私人网盘
一、华为云 Flexus X 实例:开启高效云服务新篇🌟 在云计算的广阔领域中,资源的灵活配置与卓越性能犹如璀璨星辰般闪耀。华为云 Flexus X 实例恰似一颗最为耀眼的新星,将云服务器技术推向了崭新的高度。 华为云 Flexus X 实例基于…...
【AI学习】AI绘画发展简史
无意中读了一篇发表自2022年的文章,《AI绘画何以突飞猛进? 从历史到技术突破, 一文读懂火爆的AI绘画发展史》,写的比较有意思,科普了好多我原来不知道的历史。 简单提炼一下,做个笔记。 AI绘画重要事件 2012年 Google两位大名…...
使用LangChain创建简单的语言模型应用程序【快速入门指南】
## 引言在这篇文章中,我们将展示如何使用LangChain构建一个简单的语言模型(LLM)应用程序。这个应用程序的功能是将文本从英语翻译成其他语言。尽管应用程序的逻辑相对简单,但它能够帮助我们学习如何使用LangChain进行更多复杂的功…...
嵌入式人工智能项目及人工智能应用项目——大合集列表查阅
本文的项目合集列表可能更新不及时(会及时更新),可查阅实时更新的链接如下。 嵌入式人工智能及人工智能应用项目合集实时更新链接如下: 阿齐嵌入式人工智能及人工智能应用项目合集 (kdocs.cn)https://www.kdocs.cn/l/cc97tuieys4…...
心觉:成功学就像一把刀,有什么作用关键在于使用者(一)
Hi,我是心觉,与你一起玩转潜意识、脑波音乐和吸引力法则,轻松掌控自己的人生! 挑战每日一省写作173/1000天 很多人觉得成功学是鸡汤,是没用的,甚至是骗人的 我先保持中立,不知道对不对 我们先…...
GAMES101(10节,几何)
Geometry implicit隐式几何表示: 函数f(x,y,z): 根据函数fn描述几何,遍历所有空间内 的点,如果带入xyz到函数f(x,y,z)结果0那就绘制这个点 如果xyz求值结果>0表示在几何外,0在表面,<0在几何内 构造几何csg(…...
Android 中音频焦点的使用场景及示例
Android 中音频焦点的使用场景及代码示例 一、音频焦点简介 在 Android 系统中,音频焦点(Audio Focus)是一种机制,用于管理多个应用程序同时播放音频时的冲突。当一个应用程序请求音频焦点并获得它时,其他应用程序在…...
2. JDBC驱动是什么?如何在Java项目中配置MySQL的JDBC驱动?
JDBC驱动 是一种软件组件,它使Java应用程序能够与数据库进行交互。JDBC驱动是JDBC API的实现,负责将Java程序中的标准JDBC方法调用转化为数据库特定的操作。每个数据库(如MySQL、PostgreSQL、Oracle等)都有对应的JDBC驱动程序&…...
Nginx 跨域 + 无法设置 Cookie 解决办法
今天来分享一下关于项目部署上线时怎么解决跨域问题!!! 首先感谢一下大佬的方法,才让这个困扰我很久的问题得以解决!!! 这也是我请教大佬才解决的问题,大佬和我说,这是他耗费两周才解决的问题,我这也是属于前人栽树后人乘凉了,嘿嘿嘿!!! 前端问题 前端没有携带 cookie 导致后端…...
北森笔试测评之言语理解到底难不难
前篇笔记我提到过,言语理解是最难的,有同学质疑了。言语我都会做呀,甚至有的可以搜到,而图标和图形我有的不会。这里需要指出,会做不等于作对,可以回顾到高中甚至初中的时候,感觉做的好的一般都…...
Ubuntu下beanstalkd无法绑定局域网IP地址以及消息队列beanstalkd上的error: JOB_TOO_BIG的解决
一、ubuntu下beanstalkd无法绑定局域网IP地址 今天因为业务需要,我把之前安装的beanstalkd所绑定的IP地址由127.0.0.1改成局域网IP地址,但是怪了,显示beanstalkd已经启动,查看端口监控也显示IP地址变了,但是使用telnet…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
GraphQL 实战篇:Apollo Client 配置与缓存
GraphQL 实战篇:Apollo Client 配置与缓存 上一篇:GraphQL 入门篇:基础查询语法 依旧和上一篇的笔记一样,主实操,没啥过多的细节讲解,代码具体在: https://github.com/GoldenaArcher/graphql…...
面试高频问题
文章目录 🚀 消息队列核心技术揭秘:从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"?性能背后的秘密1.1 顺序写入与零拷贝:性能的双引擎1.2 分区并行:数据的"八车道高速公路"1.3 页缓存与批量处理…...
