Python 与 C++ 混合编程

概述

  • Python 是解释型语言,在进行数学运算场景下,性能是瓶颈。
  • C++ 性能卓越,但学习门槛高且开发效率比 Python 低。
  • C++ 可以用于密集型计算并用 Python 进行调用。

实现混合编程的方式

将影响性能的核心代码用 C++ 来写,而逻辑开发由 Python 完成。

ctypes 的使用方法

  1. 编写 C++ 文件(CalculatePI.cpp):
#include <iostream>
#include <random>

// 比如在C++中调用C库函数,就需要在C++程序中用extern "C"声明要引用的函数。
// 这是给链接器用的,告诉链接器在链接的时候用C函数规范来链接。
// extern修饰符可用于指示C或者C++函数的调用规范。
extern "C"{
    double get_pi(int total) {
        int count = 0;
        std::default_random_engine gen;
        std::uniform_real_distribution<double> dist(0, 1);

        for (int i = 0; i < total; ++i) {
            double x = dist(gen);
            double y = dist(gen);
            double distance = sqrt(x * x + y * y);
            if (distance <= 1) {
                count += 1;
            }
        }

        double pi = 4.0 * count / total; //此处如果写成4,则计算结果为整数;写成4.0,则计算结果为浮点数。
        printf("%d个随机点时,π是:%f", total, pi);

        return pi;
    }
}

  1. 将 C++ 文件(CalculatePI.cpp)编译成动态链接库(CalculatePI.so):
g++ -shared -fPIC CalculatePI.cpp -o CalculatePI.so

命令解释:
gcc c语言编译命令
g++ c++语言编译命令
参数 -shared 共享的
参数 -fPIC 告诉编绎器使用 GOT 和 PLT 的方法重定位
参数 -o CalculatePI.so 输出 CalculatePI.so 文件

  1. 使用 Python 加载动态链接库,调用 C++ 函数(CalculatePI.py):
from ctypes import cdll

if __name__ == '__main__':
    # 加载动态链接库
    lib = cdll.LoadLibrary('./CalculatePI.so')
    # 调用C++函数
    print(lib.get_pi(100000000))

注意:打印函数 get_pi 的返回值 pi 有点问题,打印出来的值不对,暂时没找到原因。

pythran 的使用方法

  1. 编写 Python 文件(CalculatePI.py):
# -*- coding: gbk -*-


import random


def get_pi(total: int) -> float:
    """
    蒙特卡罗方法计算PI值:
    有一个半径为r=1的圆和边长为1的正方形,圆的面积为 πr^2=π,则正方形内部的相切圆的面积为整个圆的1/4,也就是 π/4,
    正方形的面积为1。然后我们向正方形中随机打点,就会有一定的概率落在圆中。
    这样我们就可以得到落在圆中的概率就是=圆的面积/正方形面积=π/4,那么就可以推出圆周率的计算公式:
    π=4*落在圆中的概率=4*落在圆中的点数/总点数,落在圆中的点可以定义为距离圆点小于1的点。
    """

    count = 0
    for i in range(total):
        x = random.random()
        y = random.random()
        distance = (x**2 + y**2)**0.5
        if distance <= 1:
            count += 1

    return 4*count/total

  1. 将 Python 文件(CalculatePI.py)翻译成 C++ 头文件(CalculatePI.hpp):
pythran -e CalculatePI.py -p pythran.optimizations.ConstantFolding -o CalculatePI.hpp

命令解释:
参数 -e 只运行翻译,不编译
参数 -p pythran.optimizations.ConstantFolding 在代码生成之前应用常量合并优化
参数 -o CalculatePI.hpp 输出 CalculatePI.hpp 文件

注意:

  • pythran 无法支持所有 python 的功能,只有矩阵计算与数学的数据处理,支持较好。
  • 如果 Python 文件包含中文字符,则需要在文件顶部加上# -*- coding: gbk -*-,否则翻译会报错。
  1. 编写 C++ 文件(CalculatePI.cpp)include C++ 头文件(.hpp)并调用里面的函数:
#include "CalculatePI.hpp"
#include <stdio.h>
#include <time.h>

using namespace __pythran_CalculatePI;

int main()
{
    time_t start_time = time(NULL);
    int total = 100000000;
    float pi = get_pi()(total);
    printf("%d个随机点时,π是:%f", total, pi);
    time_t end_time = time(NULL);
    printf("\n程序运行时间:%d秒", end_time - start_time);
    return 0;
}

  1. 将 C++ 文件(CalculatePI.cpp)编译成可执行文件(CalculatePI.exe):
`pythran-config --compiler --cflags` -std=c++11 -fexec-charset=gbk CalculatePI.cpp -o CalculatePI.exe

命令解释:
参数 pythran-config --compiler --cflags 编译需要的库
参数 -std=c++11 使用 c++11 标准编译
参数 -fexec-charset=gbk 使用 gbk 字符集编译
参数 -o CalculatePI.exe 输出 CalculatePI.exe 文件

注意:

  • Windows 需要安装 MinGW。
  • Windows 需要先执行命令pythran-config --compiler --cflags查看编译需要的库,然后再执行命令g++ -DENABLE_PYTHON_MODULE -D__PYTHRAN__=3 -DPYTHRAN_BLAS_NONE -Ie:\jetbrains\pycharmprojects\myvenv\venv20240503\lib\site-packages/pythran -Ie:\jetbrains\pycharmprojects\myvenv\venv20240503\lib\site-packages\numpy\core\include -Ie:\jetbrains\pycharmprojects\myvenv\venv20240503\lib\site-packages\numpy\core\include -IE:\Python\include -std=c++11 -fexec-charset=gbk CalculatePI.cpp -o CalculatePI.exe进行编译。
  1. 运行可执行文件(CalculatePI.exe):
    在这里插入图片描述
  • 21
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值