【问题标题】:Boost Python: stop interpreterBoost Python:停止解释器
【发布时间】:2015-01-16 14:23:56
【问题描述】:

within C++ 中通过 Boost Python 调用 Python 方法后,有什么方法可以停止正在运行的 Python 解释器?

我想中断通话有两个原因:

  1. 如果超时期限已过(即脚本运行“过长”)。
  2. 如果另一个(并行运行的)Python 脚本失败。

我在网络上和 Boost 文档中的搜索没有出现任何结果,但另一方面,我有时很难在 Boost 文档中找到正确的段落...

我从StackOverflow question 得到的唯一“想法”。这个想法是向脚本发送信号,但由于解释器在我的 C++ 进程中运行,这可能不是一个可行的选择?!

我正在做以下事情:

const boost::filesystem::path pythonScriptPath = /* Path to the script I want to execute a function from. */
const std::string pythonFunctionName = /* Name of the Python function to call. */;

boost::python::object mainModule = boost::python::import("__main__");
boost::python::object mainNameSpace = mainModule.attr("__dict__");

boost::python::dict locals;
locals["moduleName"] = pythonScriptPath.stem().string();
locals["modulePath"] = pythonScriptPath.string();

std::stringstream importModuleStream;
importModuleStream
    << "import imp\n"
    << "newModule = imp.load_module(moduleName, open(modulePath), modulePath, ('py', 'U', imp.PY_SOURCE))\n";

boost::python::exec(importModuleStream.str().c_str(), mainNameSpace, locals);

auto pythonScript = locals["newModule"];

auto pythonFunction = pythonScript_.attr(pythonFunctionName .c_str());
pythonFunction(/* args */);

现在的问题是:

我可以在触发 pythonFunction() 后中断/中止它的执行吗? 如果我调用它的方式不可行,是否有另一种方法可以使用 Boost Python 调用 Python 函数,以便我可以中止调用?

我在 Linux 下运行(以防万一这启用了一些依赖于平台的解决方案,我会非常喜欢)。

【问题讨论】:

    标签: python c++ linux boost boost-python


    【解决方案1】:

    没有找到了真正的“从外部停止解释器”的方法。 但是我创建了一个解决方法,至少可以在我的情况下完成工作。也许它会帮助别人......

    我的想法是我在 Python 脚本中有一个线程,它什么都不做,只是等待被唤醒。它被从 C++ 中调用“中止”函数唤醒。一旦它醒来,它就会从内部杀死脚本。在这个例子中,我选择了一种粗略的方法来停止脚本:

    os._exit(1)

    确实有更好的方法可以做到这一点,但这超出了这里的重点。整个 abort 和 terminate 的东西也可以包装得更好,但再一次:我只是想勾勒一下这个想法。

    我的测试 Python 脚本如下所示:

    import threading
    import time
    import os
    
    def abort():
        global run
        run = False
        global condition
        with condition:    
            condition.notify()
    
    def threadBlock():
        while True:
            print( "Blocking!" )
            time.sleep(3)
    
    def threadTerminate():    
        while run:
            global condition
            with condition:
                condition.wait()
    
        global kill
        if kill:
            os._exit(1)
    
    def myEntryFunction()
        blockingThread = threading.Thread( target = threadBlock )
        terminatingThread = threading.Thread( target = threadTerminate )
    
        blockingThread.start()
        terminatingThread.start()
    
        threadBlock().join()
        global kill
        kill = False
        global condition
        with condition:    
            condition.notify()      
        terminatingThread.join()
    
    
    
    run = True;
    kill = True;
    condition = threading.Condition()
    

    C++ 中,我像这样杀死脚本:

    // other code (see question)
    
    std::thread killer([&pythonScript] () {
        std::chrono::seconds d(15);
        std::this_thread::sleep_for(d);
        AcquireGIL gil;
        pythonScript.executeFunction("abort");          
    });
    
    pythonFunction(/* args */);
    

    AcquireGIL 看起来像这样:

    #include <boost/python.hpp>
    
    class AcquireGIL final
    {
    public:
        AcquireGIL();
        ~AcquireGIL();
    
    
    private:
        PyGILState_STATE gilState_;
    };
    
    AcquireGIL::AcquireGIL()
    : gilState_(PyGILState_Ensure()) {
        // nothing to do...
    }
    
    AcquireGIL::~AcquireGIL() {
        PyGILState_Release(gilState_);
    }
    

    编辑

    不同(相似)的方法

    在我的脚本的入口函数中,我启动了一个线程作为daemon,它调用了一个辅助函数。辅助函数调用一个工作方法(它可以做我真正想做的事情)。 worker 方法返回后,helper 向条件变量发出信号。主线程只是等待这个条件。如果我想从外部中止,我也只是通知条件。当主线程结束时,辅助线程已经结束或者被外部中止,都会被清理掉。

    注意

    如果发生中止,辅助线程将无法正确清理。所以你必须处理它或手动处理它。

    【讨论】:

    • 你为什么不把os._exit(1) 放到abort 函数中呢? os._exit(1) 是否仅在从入口点上下文(即从等待中止的线程)调用时才有效?
    • @peschü:是的,我认为您可以直接从(C++)线程调用os._exit(1)。我想额外的线程源于我尝试过的以前的方法,我的目标是更优雅地停止解释器,然后终止整个过程(包括 C++ 框架)。这也是“不同(相似)方法”试图实现的目标:停止 Python 代码,而周围的 C++ 应用程序继续运行。
    猜你喜欢
    • 2015-05-04
    • 1970-01-01
    • 1970-01-01
    • 2012-09-11
    • 2023-04-05
    • 1970-01-01
    • 2011-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多