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

news/2025/1/15 22:06:29/

大纲

  • 代码结构
    • 初始化 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 + bresult = 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 interpretergstate = PyGILState_Ensure(); // Acquire GILstd::cout << "Python interpreter initialized." << std::endl;}~PythonInterpreter() {PyGILState_Release(gstate); // Release GILPy_Finalize(); // Cleanup sectionstd::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 + bresult = 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.ppmy.cn/news/1520969.html

相关文章

Android11 MTK 安装apk时进行密码验证

1、客户需求 客户要求&#xff0c;在安装apk文件时&#xff0c;进行密码验证。apk文件来源包括浏览器下载、内存中、外接SDK中、adb命令安装等。之后在测试过程&#xff0c;又添加了一个限制&#xff0c;输入错误密码超过3次&#xff0c;则放弃本次安装。2、解决 路径&#xff…

Prometheus与Grafana入门:从安装到基础监控的完整指南

Prometheus与Grafana入门&#xff1a;从安装到基础监控的完整指南 Prometheus 和 Grafana 是现代监控系统的黄金组合。Prometheus 作为一个开源的监控系统和时间序列数据库&#xff0c;以其强大的指标收集和查询能力广泛应用于云原生环境。而 Grafana 则是一个用于数据可视化和…

SQL Server 中 事务( Transaction )

在 SQL Server 中&#xff0c;Transaction&#xff08;事务&#xff09;是一种处理单位&#xff0c;它由一系列操作组成&#xff0c;这些操作要么全部成功&#xff0c;要么全部失败。事务是数据库管理系统中的一个核心概念&#xff0c;用于确保数据的完整性和一致性。 事务具有…

Linux 进程等待与替换

✏️ 代码引入&#xff1a; #include <stdio.h> #include <unistd.h> // _exit()要此头文件&#xff0c;使用方法与 exit()类似 #include <stdlib.h> // exit(),要此头文件// int fun() //{ // printf("call fun function done!\n"); // retu…

使用 Monai Bundle 和 Model Zoo 对医学影像数据进行分类-全脑133个结构分割

使用 Monai Bundle 和 Model Zoo 对医学影像数据进行分类-全脑133个结构分割 文章目录 导读Monai Bundle 和 Model Zoo简单介绍基于monai bundle的MRI全脑分割模型简介模型描述模型训练细节训练数据注意事项电脑配置完整的133个脑结构列表在3D slicer使用全脑结构分割模型完整的…

MySQL数据备份策略审计:确保数据安全与合规性

在企业环境中&#xff0c;数据备份策略的审计是确保数据安全、提高数据管理效率和满足合规要求的重要环节。MySQL作为广泛使用的数据库系统&#xff0c;其备份策略的审计可以帮助组织验证备份操作的有效性、监控备份过程并确保数据的完整性和可用性。本文将详细介绍如何在MySQL…

解决:axios 请求头url传参数组时发生400错误

一、前言 axios封装的网络请求&#xff0c;url传参时&#xff0c;数组作为参数传递&#xff0c;发生400错误请求时数组参数转url会保留 [] 二、原因 RFC3986&#xff1a;除了 数字 字母 -_.~ 不会被转义&#xff0c;其他字符都会被以百分号&#xff08;%&#xff09;后跟两位…

【Python机器学习】NLP词频背后的含义——距离和相似度

我们可以使用相似度评分&#xff08;和距离&#xff09;&#xff0c;根据两篇文档的表示向量间的相似度&#xff08;或距离&#xff09;来判断文档间有多相似。 我们可以使用相似度评分&#xff08;和举例&#xff09;来查看LSA主题模型与高维TF-IDF模型之间的一致性。在去掉了…