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

大纲

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

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

代码结构

初始化 Python 解释器

cpp 复制代码
Py_Initialize();

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

获取 GIL

cpp 复制代码
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 模块并执行代码

cpp 复制代码
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

cpp 复制代码
PyGILState_Release(gstate);

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

终止 Python 解释器

cpp 复制代码
Py_Finalize();

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

完整代码

cpp 复制代码
#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的内容。

bash 复制代码
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

相关推荐
wregjru6 分钟前
【QT】4.QWidget控件(2)
c++
浅念-11 分钟前
C++入门(2)
开发语言·c++·经验分享·笔记·学习
ZH154558913112 分钟前
Flutter for OpenHarmony Python学习助手实战:面向对象编程实战的实现
python·学习·flutter
玄同76512 分钟前
SQLite + LLM:大模型应用落地的轻量级数据存储方案
jvm·数据库·人工智能·python·语言模型·sqlite·知识图谱
User_芊芊君子17 分钟前
CANN010:PyASC Python编程接口—简化AI算子开发的Python框架
开发语言·人工智能·python
小羊不会打字19 分钟前
CANN 生态中的跨框架兼容桥梁:`onnx-adapter` 项目实现无缝模型迁移
c++·深度学习
Max_uuc28 分钟前
【C++ 硬核】打破嵌入式 STL 禁忌:利用 std::pmr 在“栈”上运行 std::vector
开发语言·jvm·c++
白日做梦Q28 分钟前
Anchor-free检测器全解析:CenterNet vs FCOS
python·深度学习·神经网络·目标检测·机器学习
近津薪荼30 分钟前
dfs专题4——二叉树的深搜(验证二叉搜索树)
c++·学习·算法·深度优先
喵手42 分钟前
Python爬虫实战:公共自行车站点智能采集系统 - 从零构建生产级爬虫的完整实战(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·采集公共自行车站点·公共自行车站点智能采集系统·采集公共自行车站点导出csv