来自IPython笔记本中多线程扩展的实时输出

时间:2015-05-16 15:08:17

标签: python multithreading ipython ipython-notebook gil

我有一个c ++函数,它生成一个子线程来提供异步输出(最终这将用于实现报告多线程算法状态的进度监视器)。我希望子线程能够输出到任何地方,包括IPython笔记本。出于这个原因,我为子线程提供了一个接收字符串的回调例程。如果我想输出到Python标准输出,我使用指向暴露的cython例程的指针(使用api关键字)初始化此回调。

我花了一些时间才能正确实现允许我从子线程执行Python代码的所有GIL簿记,但最终我得到的代码在经典的Python提示符下工作。工作意味着每半秒(或多或少)我在Python提示符下从子线程获得更新输出。

问题在于,当我从IPython qtconsole或IPython笔记本执行此代码时,输​​出在函数返回之前不会出现。此时所有输出都会立即显示(这显然不适用于进度监视器)。

我怀疑这与GIL如何从Python内核传递到IPython内核端客户端有关?如何允许内核端IPython客户端将新输出发送到笔记本?

pymontor.hpp

的内容
#include "Python.h"
#include "compel_api.h"

void printSomeOutput(PyObject *callable);
void printSomeOutputMT(PyObject *callable);

pymonitor.cpp

的内容
#include "pymonitor.hpp"
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp> 

struct Worker {
    PyObject *callback;
    size_t n;
    void operator()()
    {
        std::string msg = "Hello!";
        for(size_t i = 0; i < n; ++i)
        {
            boost::this_thread::sleep(boost::posix_time::milliseconds(500));
            PyGILState_STATE gstate;
            gstate = PyGILState_Ensure();
            cy_print_message(msg, callable);
            PyGILState_Release(gstate);
        }
    }
};

void printSomeOutputMT(PyObject *callable)
{
    import_compel();
    Py_INCREF(callable);
    Worker w;
    w.callable = callable;
    w.n = 5;
    PyEval_InitThreads();
    Py_BEGIN_ALLOW_THREADS
    boost::thread thr(w);
    thr.join();
    Py_END_ALLOW_THREADS
    Py_DECREF(callable);
}

compel.pdx的内容:

cdef extern from "pymonitor.hpp" namespace "compel":
    cdef void printSomeOutputMT(object callable)

compel.pyx的内容:

cdef public api cy_print_message(string message, object callback):
    callback(message)

def test_printMT(object callback):
    printSomeOutputMT(callback)

在Python / IPython-notebook命令行测试:

from compel import *
def f(m):
    import sys
    print(m)
    sys.stdout.flush()
test_printMT(f)

0 个答案:

没有答案