fra*_*ans 6 multithreading boost-python python-3.x
我有一个很小的 Python 脚本,它(在我看来)threading.Thread.start()由于它不会立即返回而导致行为出乎意料。
在一个线程中,我想从一个boost::python不会立即返回的基于对象调用一个方法。
为此,我像这样包装对象/方法:
import threading
import time
import my_boostpython_lib
my_cpp_object = my_boostpython_lib.my_cpp_class()
def some_fn():
# has to be here - otherwise .start() does not return
# time.sleep(1)
my_cpp_object.non_terminating_fn() # blocks
print("%x: 1" % threading.get_ident())
threading.Thread(target=some_fn).start()
print("%x: 2" % threading.get_ident()) # will not always be called!!
Run Code Online (Sandbox Code Playgroud)
只要我在 my_cpp_object.non_terminating_fn(). 如果我不这样做,.start()将像.run()直接调用一样阻塞。
在调用boost::python函数之前只打印一行是不够的,但是例如打印两行或调用time.sleep()使start()按预期立即返回。
你能解释一下这种行为吗?我将如何避免这种情况(除了sleep()在调用boost::python函数之前调用)?
这种行为(在大多数情况下,当您相信解释器/编译器中存在错误时)不是 Python 中的错误,而是一种竞争条件,涵盖了由于 Python GIL (也在此处讨论)而必须预期的行为。
一旦非 Python 函数my_cpp_object.non_terminating_fn()启动,GIL 就不会被释放,直到它返回并阻止解释器执行任何其他命令。
所以time.sleep(1)无论如何在这里没有帮助,因为my_cpp_object.non_terminating_fn()在 GIL 被释放之前,下面的代码不会被执行。
当然,如果您可以修改 C/C++ 部分,您可以按照此处boost::python所述手动释放 GIL 。
一个小例子(来自上面的链接)可能看起来像这样(在 boost::python 包装器代码中)
class scoped_gil_release {
public:
inline scoped_gil_release() {
m_thread_state = PyEval_SaveThread();
}
inline ~scoped_gil_release() {
PyEval_RestoreThread(m_thread_state);
m_thread_state = NULL;
}
private:
PyThreadState * m_thread_state;
};
int non_terminating_fn_wrapper() {
scoped_gil_release scoped;
return non_terminating_fn();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2157 次 |
| 最近记录: |