RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1018488
Accepted
Andrej Levkovitch
Andrej Levkovitch
Asked:2020-08-29 14:56:28 +0000 UTC2020-08-29 14:56:28 +0000 UTC 2020-08-29 14:56:28 +0000 UTC

从 C++ 代码调用 Python 脚本

  • 772

我阅读了一篇关于Habréс++的文章,关于在使用子解释器的多线程应用程序中使用 Python 。同时,如文章所述,这允许您提供“纯多线程”,即子解释器不会全局锁定GIL(我为重言式道歉),而是并行工作。总的来说,我决定尝试编写以下代码:

// main.cpp

#include <boost/python.hpp>
#include <cstdlib>
#include <iostream>
#include <list>
#include <mutex>
#include <thread>
#include <unistd.h>
#include <unordered_map>

class PyMainThread final {
public:
  PyMainThread()
      : mainThreadState_{nullptr} {
    ::Py_Initialize();
    ::PyEval_InitThreads();

    mainGIL_         = ::PyGILState_Ensure();
    mainThreadState_ = ::PyEval_SaveThread();
  }

  ~PyMainThread() {
    ::PyEval_RestoreThread(mainThreadState_);
    ::PyGILState_Release(mainGIL_);
  }

  PyMainThread(const PyMainThread &) = delete;
  PyMainThread &operator=(const PyMainThread &) = delete;

private:
  ::PyGILState_STATE mainGIL_;
  ::PyThreadState *  mainThreadState_;
};

static std::mutex mutex;

class PySubThread final {
public:
  PySubThread()
      : mainThreadState_{nullptr}
      , subThreadState_{nullptr}
      , newInterpreterThread_{nullptr} {
    std::lock_guard<std::mutex> lock(mutex);

    mainGIL_         = ::PyGILState_Ensure();
    mainThreadState_ = ::PyThreadState_Get();

    newInterpreterThread_ = ::Py_NewInterpreter();
    ::PyThreadState_Swap(newInterpreterThread_);

    subThreadState_ = ::PyEval_SaveThread();
    subGIL_         = ::PyGILState_Ensure();
  }

  ~PySubThread() {
    std::lock_guard<std::mutex> lock(mutex);

    ::PyGILState_Release(subGIL_);
    ::PyEval_RestoreThread(subThreadState_);

    ::Py_EndInterpreter(newInterpreterThread_);
    ::PyThreadState_Swap(mainThreadState_);

    ::PyGILState_Release(mainGIL_);
  }

  PySubThread(const PySubThread &) = delete;
  PySubThread &operator=(const PySubThread &) = delete;

private:
  ::PyGILState_STATE mainGIL_;
  ::PyGILState_STATE subGIL_;

  ::PyThreadState *mainThreadState_;
  ::PyThreadState *subThreadState_;

  ::PyThreadState *newInterpreterThread_;
};

std::unordered_map<std::thread::id, std::unique_ptr<PySubThread>> pyThreads;
std::mutex                                                        pyM;

void foo(const std::string &pythonFile, int iterationCount) {
  volatile PySubThread subThread;
  for (int i = 0; i < iterationCount; ++i) {
    try {
      // std::this_thread::sleep_for(std::chrono::milliseconds{1000});
      boost::python::object import = boost::python::import("__main__");
      boost::python::object result =
          boost::python::exec_file(pythonFile.c_str(), import.attr("__dict__"));
    } catch (boost::python::error_already_set &) {
      ::PyErr_Print();
    }
  }
}

int main(int argc, char *argv[]) {
  if (argc < 4) {
    std::cerr << "you must set script, threads and count of iterations"
              << std::endl;
    return EXIT_FAILURE;
  }

  volatile PyMainThread mainThread;

  std::list<std::thread> threads;
  for (int i = 0; i < std::atoi(argv[2]); ++i) {
    threads.emplace_back(foo, argv[1], argv[3]);
  }

  for (auto &i : threads) {
    i.join();
  }

  return EXIT_SUCCESS;
}

这是一个在代码中抽搐的python脚本:

import time


def caculate(a, b):
  return a + b


def main():
  print("sleep 2 seconds ...")
  time.sleep(2)
  print("... and calculate")
  return caculate(-10, 20)


main()

# cmake

cmake_minimum_required(VERSION 3.5)

project(tmp)

find_package(Boost COMPONENTS python37 REQUIRED)
find_package(Python3 COMPONENTS Development REQUIRED)
find_package(Threads REQUIRED)

add_executable(${PROJECT_NAME} main.cpp)
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_11)
target_link_libraries(${PROJECT_NAME} PRIVATE
  Boost::boost
  ${Python3_LIBRARIES}
  ${Boost_LIBRARIES}
  Threads::Threads
  )
target_include_directories(${PROJECT_NAME} PRIVATE ${Python3_INCLUDE_DIRS})

当在多个线程中运行时,一切正常,如文章中所述,但是!注意с++代码中的第 88 行。此行将 Python 子解释器线程暂停一秒钟。如果取消注释,程序将挂起并且永远不会完成。同时,无法检测到程序停止的地方(恕我直言,这是在其中一个子解释器的构造函数中获取 GIL),使用调试器,因为当我逐步执行程序时,它正常结束.

基本上我有两个问题:

1)文章中所说的是否正确?

2) 确保在代码中并行执行 Python 脚本(无锁)如何正确(如果可能)c++?

c++
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    pepsicoca1
    2020-08-29T17:46:12Z2020-08-29T17:46:12Z

    确保在 c++ 代码中并行执行 Python 脚本(没有锁)是正确的(如果可能的话)?

    但没办法。你不能绕过 Python 中的 GIL。如果您在程序中需要多个解释器,请使用该项目:

    https://sourceforge.net/projects/obasic/

    这个解释器不是真正的 Python,而是 Basic。该解释器被设计为一个单独的 C++ 类,并在其类实例中包含其所有表。因此,在用户程序中,您可以拥有多个(理论上,只要您喜欢)解释器类的实例,它们不以任何方式相互依赖。因此,没有 GIL,您可以在解释器的不同实例中运行不同的脚本。当然,如果脚本引用用户程序的相同结构,那么这里可能需要同步。但这是一个完全不同的故事。

    • 0

相关问题

  • C++ 和循环依赖

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5