Python 使用 Cython 对函数加速并调用 C++ 代码

前言

使用c++写好的库,用python调用,速度怎么样?
C++ 库与 Python 结合使用的常见的方式
Cython 是一个强大的工具,可以将 Python 代码编译为 C 或 C++ 扩展模块,从而显著提高性能。下面是Cython 的使用示例。
在这里插入图片描述

1、准备工作

1.1 安装 Cython

确保你已经安装了 Cython:

pip install cython
1.2 示例代码结构
  • 创建C++ 文件 math.cpp和头文件math.h
  • 创建math_cython.pyx ,用于定义 Python 和 C++ 的接口。
  • 创建setup.py 文件,用于编译 Cython 和 C++ 代码。
  • 创建test.py文件,用于测试。
Cython_Demo
|-- math.cpp
|-- math.h
|-- math_cython.pyx		
|-- setup.py
`-- test.py

2、代码示例

2.1 math.h
#ifndef MATH_H
#define MATH_H

int add(int a,int b);

#endif //MATH_H
2.2 math.cpp
#include "math.h"

int add(int a,int b){
    return a+b;
}
2.3 math_cython.pyx
#定义外部C++函数
cdef extern from "math.h":
    int add(int a,int b)

#封装成python可调用函数
def py_add(int a, int b):
    return add(a,b)

def py_add_loop(int interations, int a, int b):
    cdef int i
    cdef int result = 0
    for i in range(interations):
        result += add(a,b)
    return result
2.4 setup.py
from setuptools import setup,Extension
from Cython.Build import cythonize

# 定义扩展模块
ext_modules = [
        Extension(
            name = "math_cython",                       #模块名城
            sources = ["math_cython.pyx","math.cpp"],   #包含Cython和C++文件
            language="c++",                             #指定语言为 C++
            )
        ]

# 编译扩展模块
setup(
    name="math_cython",
    ext_modules=cythonize(ext_modules, compiler_directives={'language_level': "3", 'boundscheck': False, 'wraparound': False}),
    )

2.5 test.py
import timeit
import math_cython

# 纯 Python 版本
def py_add(a, b):
    return a + b
def test_python():
    result = 0
    for _ in range(1000000):
        result +=py_add(3, 4)
    # print(f"{test_python.__name__}:{result}")

# Cython 版本
def test_cython():
    result = 0
    for _ in range(1000000):
        result +=math_cython.py_add(3, 4)
    # print(f"{test_cython.__name__}:{result}")

def test_cython_loop():
    result = 0
    result = math_cython.py_add_loop(1000000,3,4)
    # print(f"{test_cython_loop.__name__}:{result}")

print("Python:",'\t', timeit.timeit(test_python, number=10))
print("Cython:",'\t',timeit.timeit(test_cython, number=10))
print("Cython loop:",'\t',timeit.timeit(test_cython_loop, number=10))

3、编译测试

3.1 编译扩展模块

运行以下命令编译扩展模块:

python setup.py build_ext --inplace
  • build_ext: 这是 setuptools 中用于构建 Python 扩展模块(通常是由 C 或 C++ 代码编写的模块)的命令。
  • --inplace: 此选项告诉 build_ext 命令将编译后的扩展模块直接放置在当前包目录中(即与源代码相同的目录),而不是放置在默认的构建目录下(通常是项目根目录下的 build/ 文件夹)。

扩展模块编译成功后的项目结构如下,math_cython.cpython-312-x86_64-linux-gnu.so就是test.pyimport math_cython所用到的库:

./Cython_Demo/
|-- build
|   |-- lib.linux-x86_64-cpython-312
|   |   `-- math_cython.cpython-312-x86_64-linux-gnu.so
|   `-- temp.linux-x86_64-cpython-312
|       |-- math.o
|       `-- math_cython.o
|-- math.cpp
|-- math.h
|-- math_cython.cpp
|-- math_cython.cpython-312-x86_64-linux-gnu.so
|-- math_cython.pyx
|-- setup.py
`-- test.py
3.2 性能测试
python test.py 
Python:          0.41646847798256204
Cython:          0.4275268409983255
Cython loop:     0.011464812007034197

可以看出,纯python进行1000000次加法耗时和使用Cython基本一致,但是将1000000循环逻辑移到 Cython 中的Cython loop,速度提升非常大。

4、注意事项

Cython 的性能取决于你是否充分利用了它的特性。通过以下改进,你可以显著提高 Cython 的性能。其中,避免频繁调用 Python-C 接口是提升性能最明显的方式。

4.1 检查 Cython 代码中的类型声明

Cython 的性能优势主要来自于静态类型声明和编译优化。如果你的 Cython 函数中没有明确声明变量类型,Cython 会退化为普通的 Python 代码,性能提升有限。

4.2 启用 Cython 编译器优化

在编译 Cython 代码时,可以通过设置编译选项来启用更多的优化。

setup(
    name="math_cython",
    ext_modules=cythonize(ext_modules, compiler_directives={'language_level': "3", 'boundscheck': False, 'wraparound': False}),
)
  • 优化选项:
    • boundscheck=False: 禁用数组边界检查。
    • wraparound=False: 禁用负索引支持。
    • 这些选项可以减少运行时开销,提高性能。
4.3 避免频繁调用 Python-C 接口

每次调用 Cython 函数时,Python 和 C 之间会有一定的交互开销。如果调用次数过多(如循环中调用 100 万次),这种开销会累积。

# 在 Cython 中实现循环逻辑
def py_add_loop(int iterations, int a, int b):
    cdef int i
    for i in range(iterations):
        add(a, b)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值