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

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 的执行效率可能成为瓶颈,例如:

  1. 计算密集型任务:如大规模矩阵计算、图像处理、机器学习中的核心算法等。
  2. 实时系统:需要对性能有严格要求的系统,如高频交易、实时信号处理等。
  3. 遗留代码复用:已有大量用 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.RandomStatestd::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端失效

咨询描述&#xff1a; 因PC北向窗口涉及沉浸式时&#xff0c;预计发生接口废弃导致不兼容变更&#xff0c;涉及接口setImmersiveModeEnabledState、setWindowLayoutFullSceen 如果应用支持沉浸式&#xff08;窗口全屏且隐藏状态栏&标题栏&Dock栏&#xff09;&#xff0…...

【资料分析】刷题日记1

第一套 第二个是相比2019年的增长率&#xff0c;错找为同比增长率 延申&#xff1a; 当出口和进口相比2019年的增长率相同时&#xff0c;可以用盐水解决 √ 一个假设分配&#xff08;第二次是1.4取1&#xff09;加法对比选项 基期倍数&#xff1a; 求A是B的多少倍&#x…...

nodejs+express+vue教辅课程辅助教学系统 43x2u前后端分离项目

目录 技术栈具体实现截图系统设计思路技术可行性nodejs类核心代码部分展示可行性论证研究方法解决的思路Express框架介绍源码获取/联系我 技术栈 该系统将采用B/S结构模式&#xff0c;开发软件有很多种可以用&#xff0c;本次开发用到的软件是vscode&#xff0c;用到的数据库是…...

96-javahashmap底层原理

HashMap是Java集合框架中的一个重要类&#xff0c;底层是基于哈希表实现的。哈希表是一种数据结构&#xff0c;可以通过哈希函数来提高查找、插入和删除操作的效率。 以下是HashMap底层实现的一些关键点&#xff1a; 哈希算法&#xff1a;HashMap使用哈希算法来计算键的哈希值…...

AI逻辑推理入门

参考数据鲸 (linklearner.com) 1. 跑通baseline 报名 申领大模型API 模型服务灵积-API-KEY管理 (aliyun.com) 跑通代码 在anaconda新建名为“LLM”的环境,并安装好相应包后,在jupyter notebook上运行baseline01.ipynb 2. 赛题解读 一般情况下,拿到一个赛题之后,我们需…...

力扣3014.输入单词需要的最少按键次数I

给你一个字符串 word&#xff0c;由 不同 小写英文字母组成。 电话键盘上的按键与 不同 小写英文字母集合相映射&#xff0c;可以通过按压按键来组成单词。例如&#xff0c;按键 2 对应 ["a","b","c"]&#xff0c;我们需要按一次键来输入 "…...

【Git】远程仓库

本博客的环境是 Ubuntu/Linux 文章目录 集中式与分布式的区别远程仓库新建远程仓库克隆远程仓库向远程仓库推送从远程仓库拉取 配置Git忽略指定文件给命令配置别名 标签管理创建标签操作标签 多人协作本地分支与远程分支连接场景一场景二 集中式与分布式的区别 引荐自关于Git这…...

苹果手机铃声怎么设置自己的歌?3个方法自定义手机铃声

苹果手机内部的手机铃声库只有固定的几首铃声&#xff0c;且都是纯音乐&#xff0c;比较单调&#xff0c;并不是所有用户都喜欢这些铃声。那么&#xff0c;苹果手机铃声怎么设置自己的歌呢&#xff1f;小编这里有3个方法&#xff0c;可以教大家如何将手机铃声设置成自己喜欢的歌…...

828华为云征文|华为Flexus云服务器搭建Cloudreve私人网盘

一、华为云 Flexus X 实例&#xff1a;开启高效云服务新篇&#x1f31f; 在云计算的广阔领域中&#xff0c;资源的灵活配置与卓越性能犹如璀璨星辰般闪耀。华为云 Flexus X 实例恰似一颗最为耀眼的新星&#xff0c;将云服务器技术推向了崭新的高度。 华为云 Flexus X 实例基于…...

【AI学习】AI绘画发展简史

无意中读了一篇发表自2022年的文章&#xff0c;《AI绘画何以突飞猛进? 从历史到技术突破, 一文读懂火爆的AI绘画发展史》&#xff0c;写的比较有意思&#xff0c;科普了好多我原来不知道的历史。 简单提炼一下&#xff0c;做个笔记。 AI绘画重要事件 2012年 Google两位大名…...

使用LangChain创建简单的语言模型应用程序【快速入门指南】

## 引言在这篇文章中&#xff0c;我们将展示如何使用LangChain构建一个简单的语言模型&#xff08;LLM&#xff09;应用程序。这个应用程序的功能是将文本从英语翻译成其他语言。尽管应用程序的逻辑相对简单&#xff0c;但它能够帮助我们学习如何使用LangChain进行更多复杂的功…...

嵌入式人工智能项目及人工智能应用项目——大合集列表查阅

本文的项目合集列表可能更新不及时&#xff08;会及时更新&#xff09;&#xff0c;可查阅实时更新的链接如下。 嵌入式人工智能及人工智能应用项目合集实时更新链接如下&#xff1a; 阿齐嵌入式人工智能及人工智能应用项目合集 (kdocs.cn)https://www.kdocs.cn/l/cc97tuieys4…...

心觉:成功学就像一把刀,有什么作用关键在于使用者(一)

Hi&#xff0c;我是心觉&#xff0c;与你一起玩转潜意识、脑波音乐和吸引力法则&#xff0c;轻松掌控自己的人生&#xff01; 挑战每日一省写作173/1000天 很多人觉得成功学是鸡汤&#xff0c;是没用的&#xff0c;甚至是骗人的 我先保持中立&#xff0c;不知道对不对 我们先…...

GAMES101(10节,几何)

Geometry implicit隐式几何表示&#xff1a; 函数f(x,y,z)&#xff1a; 根据函数fn描述几何&#xff0c;遍历所有空间内 的点&#xff0c;如果带入xyz到函数f(x,y,z)结果0那就绘制这个点 如果xyz求值结果>0表示在几何外&#xff0c;0在表面,<0在几何内 构造几何csg(…...

Android 中音频焦点的使用场景及示例

Android 中音频焦点的使用场景及代码示例 一、音频焦点简介 在 Android 系统中&#xff0c;音频焦点&#xff08;Audio Focus&#xff09;是一种机制&#xff0c;用于管理多个应用程序同时播放音频时的冲突。当一个应用程序请求音频焦点并获得它时&#xff0c;其他应用程序在…...

2. JDBC驱动是什么?如何在Java项目中配置MySQL的JDBC驱动?

JDBC驱动 是一种软件组件&#xff0c;它使Java应用程序能够与数据库进行交互。JDBC驱动是JDBC API的实现&#xff0c;负责将Java程序中的标准JDBC方法调用转化为数据库特定的操作。每个数据库&#xff08;如MySQL、PostgreSQL、Oracle等&#xff09;都有对应的JDBC驱动程序&…...

Nginx 跨域 + 无法设置 Cookie 解决办法

今天来分享一下关于项目部署上线时怎么解决跨域问题!!! 首先感谢一下大佬的方法,才让这个困扰我很久的问题得以解决!!! 这也是我请教大佬才解决的问题,大佬和我说,这是他耗费两周才解决的问题,我这也是属于前人栽树后人乘凉了,嘿嘿嘿!!! 前端问题 前端没有携带 cookie 导致后端…...

北森笔试测评之言语理解到底难不难

前篇笔记我提到过&#xff0c;言语理解是最难的&#xff0c;有同学质疑了。言语我都会做呀&#xff0c;甚至有的可以搜到&#xff0c;而图标和图形我有的不会。这里需要指出&#xff0c;会做不等于作对&#xff0c;可以回顾到高中甚至初中的时候&#xff0c;感觉做的好的一般都…...

Ubuntu下beanstalkd无法绑定局域网IP地址以及消息队列beanstalkd上的error: JOB_TOO_BIG的解决

一、ubuntu下beanstalkd无法绑定局域网IP地址 今天因为业务需要&#xff0c;我把之前安装的beanstalkd所绑定的IP地址由127.0.0.1改成局域网IP地址&#xff0c;但是怪了&#xff0c;显示beanstalkd已经启动&#xff0c;查看端口监控也显示IP地址变了&#xff0c;但是使用telnet…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

MySQL:分区的基本使用

目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区&#xff08;Partitioning&#xff09;是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分&#xff08;分区&#xff09;可以独立存储、管理和优化&#xff0c;…...

【Linux】自动化构建-Make/Makefile

前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具&#xff1a;make/makfile 1.背景 在一个工程中源文件不计其数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;mak…...