代码之家  ›  专栏  ›  技术社区  ›  Mike

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

  •  2
  • Mike  · 技术社区  · 7 年前

    #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 + 1\n"
                         "  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机器上试过了。一方面,它大约有四分之三的时间失败;另一方面,大约有十分之一的时间。最常见的故障是没有帮助的:

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

    Boost Pythnon文档中有几个诱人的调用涉及concurrancy,但我尝试过的组合都没有帮助。这个 global interpreter lock 相同的 Python解释器线程,除非我误解了它。我想要两个完全独立的Python解释器同时运行。

    This example 很接近,但使用两个单独的C线程,偶尔调用Python来完成一些工作。我试图同时运行两个独立的Python进程。

    This question 相似,但给出的细节较少。在我的例子中,Python解释器用于将需要在超级计算机上运行相当长时间的外部进程联系在一起;他们不需要回拨到我的C++应用程序中。完成后,C++应用程序将从外部拖放文件中收集并显示结果。

    1 回复  |  直到 7 年前
        1
  •  0
  •   Mike    7 年前

    哎呀,约翰是科伦特。我们从未找到在Boost 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 + 1\n"
                         "  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进程都需要很短的时间,那么这是可行的,但在我们的应用程序中不是这样的,所以我们拒绝了这个替代方案。