两个并发的 Python 进程可以在 Boost Python 中运行吗?

Can two concurrent Python processes run in Boost Python?

本文关键字:Python Boost 运行 进程 两个 并发      更新时间:2023-10-16

我正在尝试从boost::p ython在Python解释器中运行并发Python脚本。下面是一个简短的示例程序:

#include <Python.h>
#include <boost/python/exec.hpp>
#include <iostream>
#include <thread>
#include <boost/python/extract.hpp>
#include <boost/python/import.hpp>
#include <boost/python/object.hpp>
int main(int argc, char const *argv[]) {
const char *prog = "def ack(m, n):n"
"  if m == 0:n"
"    return n + 1n"
"  elif n == 0:n"
"    return ack(m - 1, 1)n"
"  else:n"
"    return ack(m - 1, ack(m, n - 1))";
Py_Initialize();
try {
std::thread t1([&prog]() {
std::cout << "t1" << std::endl;
boost::python::object mainModule = boost::python::import("__main__");
boost::python::object mainNamespace = mainModule.attr("__dict__");
boost::python::exec(prog, mainNamespace, mainNamespace);
int val = boost::python::extract<int>(
boost::python::eval("ack(3,3)", mainNamespace, mainNamespace));
std::cout << "t1 result: " << val << std::endl;
});
std::thread t2([&prog]() {
std::cout << "t2" << std::endl;
boost::python::object mainModule = boost::python::import("__main__");
boost::python::object mainNamespace = mainModule.attr("__dict__");
boost::python::exec(prog, mainNamespace, mainNamespace);
int val = boost::python::extract<int>(
boost::python::eval("ack(3,4)", mainNamespace, mainNamespace));
std::cout << "t2 result: " << val << std::endl;
});
t1.join();
t2.join();
} catch (boost::python::error_already_set const &e) {
PyErr_Print();
}
return 0;
}

问题是程序间歇性地失败。我已经在两个不同的Linux机器上尝试过了。一方面,它大约 3/4 的时间失败;另一方面大约 1/10 的时间。最常见的故障是不太有帮助的:

RUN FINISHED; Segmentation fault; core dumped; real time: 60ms; user: 0ms; system: 0ms

在 Boost Pythnon 文档中有几个诱人的调用提到了并发性,但我尝试过的组合都没有帮助。全局解释器锁 (GIL( 似乎旨在允许C++访问相同的Python 解释器线程,除非我误解了它。我希望两个完全独立的Python解释器同时运行。

此示例很接近,但使用两个单独的 C 线程,偶尔调用 Python 来执行一些工作。我正在尝试同时运行两个单独的 Python 进程。

这个问题是相似的,尽管它提供的细节较少。就我而言,Python 解释器用于将外部进程绑定在一起,这些进程在超级计算机上运行需要相当长的时间;他们不需要回拨我的C++应用。完成后,C++应用程序将从外部拖放文件中收集并显示结果。

AFAIK,John是相关的。我们从来没有找到在Boost Python中运行两个并发Python项目的方法。有三种方法可以回避此问题。这是第一个:运行两个不同的Python 解释器。

#include <Python.h>
#include <boost/python/exec.hpp>
#include <iostream>
#include <thread>
#include <sys/wait.h>
#include <boost/python/extract.hpp>
#include <boost/python/import.hpp>
#include <boost/python/object.hpp>
void python (std::string fork, int m, int n) {
const char *prog = "def ack(m, n):n"
"  if m == 0:n"
"    return n + 1n"
"  elif n == 0:n"
"    return ack(m - 1, 1)n"
"  else:n"
"    return ack(m - 1, ack(m, n - 1))";
Py_Initialize();
try {
std::cout << fork << std::endl;
boost::python::object mainModule = boost::python::import("__main__");
boost::python::object mainNamespace = mainModule.attr("__dict__");
std::stringstream commandstream;
commandstream << "ack(" << m << "," << n << ")";
std::string command = commandstream.str();
boost::python::exec(prog, mainNamespace, mainNamespace);
int val = boost::python::extract<int>(boost::python::eval(command.c_str(), mainNamespace, mainNamespace));
std::cout << fork << " result: " << val << std::endl;
} catch (boost::python::error_already_set const &e) {
PyErr_Print();
}
}
int main (int argc, char const *argv[]) {
pid_t pid = fork();
if (pid == 0) {
python("f1", 3, 4);
} else if (pid > 0) {
python("f2", 3, 3);
int status;
waitpid(pid, &status, 0);
} else {
std::cout << "Fork failed." << std::endl;
}
return 0;
}

第二种方法,也是我们最终使用的方法,是将运行 Python 解释器的代码放在外部可执行文件中并运行它。

第三种是阻塞线程,直到第一个 Python 进程完成。如果每个 Python 进程预计需要非常短的时间,这是可行的,但在我们的应用程序中并非如此,所以我们拒绝了这种替代方案。