1. 引言
在 Python 项目中,部分计算密集或频繁调用的代码可能会成为性能瓶颈,同时部分核心模块因保密需求不宜直接暴露源码。对此,我们可以将这部分代码使用 C++ 重写,并借助 pybind11 将其封装成 Python 模块,从而达到如下目的:
- 提高运行速度:充分利用 C++ 编译优化,以及低级别资源管理提升计算效率。
- 增强保密性:C++ 的编译产物(.so 文件等)较难被逆向,降低关键算法泄露风险。
- 保持项目整体风格:只需替换核心模块,其他 Python 代码无需大改。
同时,为了方便对比,我们保留了纯 Python 的实现,并在测试代码中对两种实现的运行速度做了比较。
2. C++ 代码与 pybind11 封装
以下示例代码展示了如何用 C++ 编写一个递归计算斐波那契数的函数以及一个简单的加法函数,并利用 pybind11 对它们进行封装。
// example.cpp
#include <pybind11/pybind11.h>
namespace py = pybind11;
// 递归计算斐波那契数,当 n 的值较大时,该函数计算速度较慢,适合作为性能对比的示例。
int fibonacci(int n) {
if (n < 2)
return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
// 简单加法函数示例
int add(int a, int b) {
return a + b;
}
PYBIND11_MODULE(example, m) {
m.doc() = "利用 pybind11 封装的 C++ 示例模块";
m.def("fibonacci", &fibonacci, "递归计算斐波那契数");
m.def("add", &add, "简单加法运算");
}
编译 C++ 模块
确保在系统中安装了支持的 C++ 编译器以及 pybind11 库,然后使用以下命令进行编译(以 g++ 为例):
c++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` example.cpp -o example`python3-config --extension-suffix`
编译成功后,会生成一个共享库文件(如 example.cpython-38-x86_64-linux-gnu.so),该文件可以直接在 Python 中导入使用。
3. 纯 Python 代码版本
为了方便对比,我们保留了纯 Python 版本的斐波那契数实现。代码如下:
# fibonacci_python.py
def fibonacci_py(n):
if n < 2:
return n
return fibonacci_py(n - 1) + fibonacci_py(n - 2)
这版实现与 C++ 中的逻辑一致,均采用递归算法计算斐波那契数。由于 Python 的解释性执行方式,在 n 较大时性能较差,正好可以用来与编译后的 C++ 模块进行性能对比。
4. 在 Python 中调用及性能对比
下面是一个完整的 Python 测试文件,通过调用纯 Python 版本和 C++ 模块分别计算斐波那契数,并对比两者的运行时间。
# test_comparison.py
import time
import example # 导入通过 pybind11 编译得到的 C++ 模块
# 纯 Python 版本的递归实现
def fibonacci_py(n):
if n < 2:
return n
return fibonacci_py(n - 1) + fibonacci_py(n - 2)
def run_speed_test(n):
print(f"=== 测试 fibonacci({n}) ===")
# 纯 Python 版本测试
start = time.perf_counter()
result_py = fibonacci_py(n)
end = time.perf_counter()
python_time = end - start
print(f"纯 Python 计算结果:{result_py},耗时:{python_time:.6f} 秒")
# 使用 C++ 模块测试
start = time.perf_counter()
result_cpp = example.fibonacci(n)
end = time.perf_counter()
cpp_time = end - start
print(f"C++ 计算结果(pybind11 模块):{result_cpp},耗时:{cpp_time:.6f} 秒")
print(f"加速比: {python_time / cpp_time:.2f}x\n")
if __name__ == "__main__":
# 选择一个较大的 n 值来测试,n 值太小可能看不出太大区别
test_value = 35
run_speed_test(test_value)
执行这个测试脚本你会得到类似下面的输出(具体运行时间因系统环境、CPU 性能及编译优化而异):
=== 测试 fibonacci(35) ===
纯 Python 计算结果:9227465,耗时:3.756123 秒
C++ 计算结果(pybind11 模块):9227465,耗时:0.073512 秒
加速比: 51.12x
从结果中可以明显看出,使用 C++ 的实现比纯 Python 实现快得多,同时两者计算结果一致,证明了在保持逻辑一致的前提下,C++ 模块能够有效提升性能。
5. 总结
通过上述方案,我们既保留了纯 Python 的实现,也实现了利用 C++ 与 pybind11 封装的高性能模块,并且对比测试了两者的执行速度。该方案具有以下优点:
- 性能提升:核心算法经 C++ 编译优化后,运行速度显著加快。
- 保密增强:关键算法封装在编译后的共享库中,不易直接还原源码。
- 无缝集成:通过 pybind11 将 C++ 功能导出为 Python 模块,现有 Python 项目几乎无需做改动。
这种采用 C++ 与 pybind11 混合开发的方案,特别适用于那些既有高性能需求又有核心逻辑保密需求的项目。希望本文的示例与说明能为你的项目提供有益的参考和帮助!