C++和Python混合编程——C++调用Python入门

news2024/12/27 13:45:53

大纲

  • 代码结构
    • 初始化 Python 解释器
    • 获取 GIL
      • 为什么需要 GIL?
      • GIL 的影响
    • 导入 Python 模块并执行代码
    • 释放 GIL
    • 终止 Python 解释器
  • 完整代码
  • 编译
  • 执行结果
  • 项目地址

在《C++和Python混合编程——Python调用C++入门》一文中,我们熟悉了Python调用C++编译的动态库的方法。但是作为混合编程,也必然要有反向的过程——C++调用Python代码。本文我们将介绍如何使用boost.python库实现该功能。

代码结构

初始化 Python 解释器

Py_Initialize();

在程序开始时初始化 Python 解释器,确保可以调用其他 Python C API 函数。它会设置 Python 解释器的内部状态,加载内置模块,并准备好执行 Python 代码。

获取 GIL

PyGILState_STATE gstate;
gstate = PyGILState_Ensure();

GIL(Global Interpreter Lock,全局解释器锁)是 Python 解释器中的一个机制,用于在多线程环境中保护访问 Python 对象的共享资源。GIL 确保在任何时刻只有一个线程可以执行 Python 字节码,从而避免了多线程访问共享资源时的竞争条件。

为什么需要 GIL?

Python 的内存管理不是线程安全的。为了避免多线程同时访问和修改共享数据导致的不一致性和崩溃,GIL 被引入来确保只有一个线程可以执行 Python 代码。

GIL 的影响

  • 多线程限制:由于 GIL 的存在,在 CPU 密集型任务中,多线程的性能提升有限,因为同一时刻只有一个线程在执行 Python 代码。
  • I/O 密集型任务:对于 I/O 密集型任务(如网络请求、文件读写),多线程仍然可以带来性能提升,因为 I/O 操作会释放 GIL,使其他线程有机会执行。

导入 Python 模块并执行代码

boost::python::object main_module = boost::python::import("__main__");
boost::python::object main_namespace = main_module.attr("__dict__");

std::string python_code = R"(
def add(a, b):
    return a + b

result = add(3, 4)
print(f"Result of add(3, 4) is {result}")
)";
boost::python::exec(python_code.c_str(), main_namespace);

int result = boost::python::extract<int>(main_namespace["result"]);
std::cout << "Result from Python: " << result << std::endl;

释放 GIL

PyGILState_Release(gstate);

在完成 Python 代码执行后释放 GIL。

终止 Python 解释器

Py_Finalize();

在程序结束时调用 Py_Finalize() 以清理 Python 解释器的状态,释放内存和其他资源。如果不调用 Py_Finalize(),可能会导致内存泄漏和其他资源未释放的问题。

完整代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <chrono>
#include <boost/python.hpp>

class PythonInterpreter {
public:
    PythonInterpreter() {
        Py_Initialize(); // Initialize Python interpreter
        gstate = PyGILState_Ensure(); // Acquire GIL
        std::cout << "Python interpreter initialized." << std::endl;
    }

    ~PythonInterpreter() {
        PyGILState_Release(gstate); // Release GIL
        Py_Finalize(); // Cleanup section
        std::cout << "Python interpreter finalized." << std::endl;
    }

private:
    PyGILState_STATE gstate;
};

void call_python_function() {
    using namespace boost::python;

    try {
        // 创建 PythonInterpreter 对象,自动初始化 Python 解释器
        PythonInterpreter pyInterp;
        
        // 导入 Python 模块
        object main_module = import("__main__");
        object main_namespace = main_module.attr("__dict__");

        // 定义并执行 Python 代码
        std::string python_code = R"(
def add(a, b):
    return a + b

result = add(3, 4)
print(f"Result of add(3, 4) is {result}")
)";
        exec(python_code.c_str(), main_namespace);

        // 获取并打印结果
        int result = extract<int>(main_namespace["result"]);
        std::cout << "Result from Python: " << result << std::endl;
    } catch (error_already_set) {
        PyErr_Print();
    }
}

int main() {
    call_python_function();
    return 0;
}

编译

以下是CMakeLists.txt的内容。

cmake_minimum_required(VERSION 3.12)

# 项目信息
# 最后一级目录为项目名称
get_filename_component(ProjectName ${CMAKE_CURRENT_SOURCE_DIR} NAME)
project(${ProjectName})

# 设置 CMP0148 政策
if(POLICY CMP0148)
    cmake_policy(SET CMP0148 NEW)
endif()

# 查找 Python 解释器和库
find_package(Python3 REQUIRED COMPONENTS Interpreter Development)

# 查找 Boost 库。使用 Python3_VERSION_MAJOR 和 Python3_VERSION_MINOR 变量来查找对应版本的 Boost.Python 库
find_package(Boost REQUIRED COMPONENTS python${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR})

# 添加可执行文件
add_executable(${ProjectName} main.cpp)

# 包含 Python 头文件
include_directories(${Python3_INCLUDE_DIRS})

# 链接 Boost.Python 和 Python 库
target_link_libraries(${ProjectName} ${Boost_LIBRARIES} ${Python3_LIBRARIES})

执行结果

在这里插入图片描述

项目地址

https://github.com/f304646673/cpulsplus/tree/master/boost_python/c_call_p

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2106065.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UE5 C++ 读取图片插件(一)

原来UE可以使用 static,之前不知道&#xff0c;一用就报错。 static TSharedPtr<IImageWrapper> GetImageWrapperByExtention(const FString InImagePath); //智能指针&#xff0c;方便追寻引用C,加载ImageWrapperstatic UTexture2D* LoadTexture2D(const FString& …

算法-滑动窗口技巧

文章目录 基础理论介绍长度最小的子数组无重复字符的最长字串解法1 : 哈希表计数逐步缩进解法2 : 哈希表更新下标跳跃缩进 最小覆盖字串替换子串获得平衡字符串K个不同整数的子数组 基础理论介绍 1. 滑动窗口简介 : 滑动窗口其实就是维持了一段区间(l边界与r边界), 并且对于这…

C++:构造函数、析构函数

目录 一、类的默认成员函数 二、构造函数 构造函数的特点 三、析构函数 析构函数的特点 一、类的默认成员函数 默认成员函数就是用户没有显式实现&#xff0c;编译器会自动生成的成员函数称为默认成员函数&#xff0c;一个类&#xff0c;我们不写的情况下编译器会默认生成…

Unity(2022.3.41LTS) - 动画融合术

目录 一、动画融合的概念 二、动画融合的类型 三、动画融合的实现方法 1.简介 2.创建新的图层 3.创建遮罩 4.遮罩配置 5.预览效果 6.使用代码灵活控制 7.全部代码 四、动画融合的优化和注意事项 一、动画融合的概念 在 Unity 中&#xff0c;动画融合是一种强大的技…

安装 Let‘s Encrypt certbot 生成多个域名免费 https 证书实录(linux pip 方式)

本文记录了我在华为云 EulerOS linux 云主机使用 python pip 方式安装配置 Let’s Encrypt certbot, 并为我的网站的多个域名生成免费 https 证书的整个过程, 包括 python 环境配置, 下载 certbot 及 certbot-nginx, 一次性生成多个域名的证书及注意事项, 以及最后配置 certbot…

5G农业大数据中心顶层设计

1. 政策背景与规划 国家政策大力推动大数据发展和应用&#xff0c;特别是农业农村信息化发展规划&#xff0c;强调数字化在农业现代化中的关键作用。《数字农业农村发展规划&#xff08;2019-2025年&#xff09;》明确了农业农村数字化的重要性。 2. 国际农业大数据现状 美国…

超图iServer 11i在Java中调用REST接口点线面增删改查方法

一、引入iServer的Jar包 需要到iServer安装目录/webapps/iserver/WEB-INF/lib下寻找以下几个jar包&#xff0c;把它引入到项目里&#xff1a; iserver-all-*.jar service-model-*.jar rest-sdk-*.jar然后再引入几个maven依赖包&#xff1a; <dependency><groupId&g…

MyBaits 二级缓存原理

优质博文&#xff1a;IT-BLOG-CN 一级缓存原理 默认关闭&#xff0c;一般不建议使用。为什么不建议使用我们要清楚。 先给不建议使用的原因&#xff1a; MyBatis的二级缓存是和命名空间绑定的&#xff0c;所以通常情况下每一个Mapper映射文件都拥有自己的二级缓存&#xff0c;…

关于谷歌账号的三个“错误的”问题:谷歌有客服吗?登录不了的账号如何注销?登录不了的账号绑定的手机还能注册新账号吗?

这段时间GG账号服务收到很多朋友的反馈&#xff0c;其中有一些具有典型的问题&#xff0c;而且是错误的问题——主要是对谷歌账号或者谷歌账号使用的误解&#xff0c;从而浪费了时间&#xff0c;或者走了弯路&#xff0c;或者反复试错给账号带来了更大的风险。 今天就来给大家…

Spring 框架下 Redis 数据结构的全面解析

Hello , 大家好 , 这个专栏给大家带来的是 Redis 系列 ! 本篇文章给大家带来的是如何通过 Spring 来操作 Redis 中的常见数据结构 , 以及如何通过代码执行 Redis 中的原生命令 . 本专栏旨在为初学者提供一个全面的 Redis 学习路径&#xff0c;从基础概念到实际应用&#xff0c;…

【C++题解】1088 - 求两个数M和N的最大公约数

问题四&#xff1a;1088 - 求两个数M和N的最大公约数 类型&#xff1a;需要找规律的循环。 题目描述&#xff1a; 求两个正整整数 M 和 N 的最大公约数(M&#xff0c;N都在长整型范围内&#xff09; 输入&#xff1a; 输入一行&#xff0c;包括两个正整数。 输出&#xff…

Antv a-table 表格行/列合并,在合并后的td中使用插槽slot

【需求】 这次的表格需要实现行列合并&#xff0c;并且要在合并后的 td 中使用子组件或弹出弹窗&#xff0c;难点在于&#xff1a; 1. 根据提供的data&#xff0c;自行判断是否合并项的 getRowspan方法 2. customCell 、scopedSlots 冲突导致的子组件无法展示 &#xff08…

Cesium 实战 - 自定义纹理材质 - 流动线(精灵线)

Cesium 实战 - 自定义纹理材质 - 流动线(精灵线) 核心代码完整代码在线示例Cesium 给实体对象(Entity)提供了很多实用的样式,基本满足普通项目需求; 但是作为 WebGL 引擎,肯定不够丰富,尤其是动态效果样式。 对于实体对象(Entity),可以通过自定义材质,实现各种动…

【YOLOv8系列】YOLOv8的GUI界面设计;在电脑本地实现YOLOv8的可视化交互界面设计(对摄像头的实时画面进行分类)

背景: 最近在研究YOLOv8的应用,并且已经在自己的笔记本环境中跑通了YOLOv8的检测和分类算法,训练、验证、预测等功能均已实现;也通过自己的数据集训练出了自己的模型(权重);且之前也做了一个webUI界面,对YOLOv8检测和分类的结果进行展示;但是如果在本地的GUI界面调用摄…

Python pip 更换镜像源

文章目录 1 概述1.1 默认镜像&#xff0c;速度慢&#xff0c;易报错1.2 常用国内镜像源 2 更改镜像源2.1 临时更改2.2 永久更改2.2.1 查看配置源及配置文件2.2.2 编辑 pip.ini2.2.3 配置后的效果 1 概述 1.1 默认镜像&#xff0c;速度慢&#xff0c;易报错 默认镜像&#xff…

导出硬盘所有文件名到txt文本文件——C#学习笔记

下面的示例演示如何使用递归遍历目录树。递归方法很简洁&#xff0c;但如果目录树很大且嵌套很深&#xff0c;则有可能会引起堆栈溢出异常。 对于所处理的特定异常以及在每个文件和文件夹上执行的特定操作&#xff0c;都只是作为示例提供。您应该修改此代码来满足自己特定的需…

分类学习器(Classification Learner App)MATLAB

在MATLAB中&#xff0c;分类学习器用于构建和评估分类模型。MATLAB提供了一些工具和功能&#xff0c;帮助你进行分类任务&#xff0c;例如分类学习器应用程序、统计和机器学习工具箱中的函数等。 导入数据 我们在打开应用程序之前的第一步将是导入我们将在工作区使用的数据。…

新品上市丨科学级新款制冷相机sM4040A/sM4040B

sM4040B科学级显微制冷相机 特性 sM4040B搭载了 GSENSE4040BSI 3.2 英寸图像传感器&#xff0c;针对传感器固有的热噪声&#xff0c;专门设计了高效制冷模块&#xff0c;使得相机传感器的工作温度比环境温度低达 35-40 度。针对制冷相机常见的低温结雾现象设计了防结雾机制&a…

Serverless 应用引擎 SAE 助力袋拉拉研发提效 70%

作者&#xff1a;百潼 医院环保 IOT 设备的引领者&#xff1a;机汽猫 机汽猫是⼀家致⼒于通过投放⾃助取袋设备&#xff0c;为医院场景提供新型环保袋交付⽅式的科技公司。它成⽴于 2019 年&#xff0c;旗下品牌袋拉拉&#xff08;DaiLala&#xff09;通过投放⾃助取袋机&…

《Cloud Native Data Center Networking》(云原生数据中心网络设计)读书笔记 -- 10数据中心中的BGP

本章解答以下问题&#xff1a; ASN&#xff0c;团体&#xff08;community&#xff09;&#xff0c;属性&#xff08;attribute&#xff09;&#xff0c;最佳路径这些BGP术语是什么疑似&#xff1f;在数据中心中应该使用eBGP还是iBGP?在数据中心使用BGP时&#xff0c;应采用什…