2017-08-03 15 views
2

私は、同時Pythonスクリプトをboost :: pythonのPythonインタプリタで実行しようとしています。短いサンプルプログラムは次のとおりです。同時に2つのPythonプロセスをBoost 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 + 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; 
} 

問題は、プログラムが断続的に失敗することです。私は2つの異なるLinuxボックスで試しました。 1つは、時間の約3/4に失敗します。もう1つは約10分の1です。最も一般的な障害mesaageは役に立ち未満である:

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

ブーストPythnonのconcurrancyに参照のうえドキュメントが、私は助けを試した組み合わせのいずれにおいても、いくつかの魅力的な呼び出しがあります。 global interpreter lock(GIL)は、誤解していない限り、と同じのPythonインタプリタスレッドにC++がアクセスできるようになっているようです。私は2つの完全に独立したPythonインタプリタを同時に実行したい。

This exampleは近いですが、ときどきPythonを呼び出していくつかの作業を行う2つの独立したCスレッドを使用します。私は2つの別々のPythonプロセスを同時に実行しようとしています。

This questionはそれほど詳細ではありませんが、類似しています。私の場合、Pythonインタプリタは、スーパーコンピュータで実行するのにかなりの時間を要する外部プロセスを結びつけるために使用されます。彼らは私のC++アプリケーションにコールバックする必要はありません。それらが完了すると、結果は収集され、C++アプリケーションによって外部のドロップファイルから表示されます。

+4

Pythonインタプリタは、複数のスレッドの同時実行をサポートしていません。複数のスレッドは、同じインタプリタで実行できますが、協調的な時間共有スタイルのモードでのみ実行できます。ネイティブスレッドは同時に実行できますが、インタプリタとそれに属する管理対象オブジェクトへのアクセスはGIL経由でシリアル化する必要があります。ブーストはそれを変更することはできません。 –

+0

@JohnBollingerそれは、上記の例のコードがしようとするように、スレッドではなく別のプロセスで同時にPythonの作業を行うという唯一の解決策のようです。あれは正しいですか? – ukhat

+2

はい、私の知る限りでは、Pythonインタープリタ自体で動作するコードの真の並行性は、別々のプロセスを必要とします。 –

答えて

0

AFAIK、Johnはcorrentです。 Boost Pythonで2つの並行したPythonプロジェクトを実行する方法が見つかりませんでした。この問題を回避するには3つの方法があります。最初は次のとおりです:2回実行 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; 
} 

第二の方法、そして私たちが使用して終了1は、外部実行可能ファイルにPythonインタプリタを実行して、それを実行するためのコードを配置することです。

第3は、最初のPythonプロセスが終了するまでスレッドをブロックすることです。これは、各Pythonプロセスの処理時間が非常に短いと予想される場合には実行可能ですが、アプリケーションではそうではありませんでした。

関連する問題