Python的错误? threading.Thread.start()并不总是返回 [英] Bug in Python? threading.Thread.start() does not always return
问题描述
我有一个很小的Python脚本,在我眼中,它使threading.Thread.start()
表现出异常,因为它不会立即返回.
I have a tiny Python script which (in my eyes) makes threading.Thread.start()
behave unexpectedly since it does not return immediately.
在线程内,我想从基于boost::python
的对象中调用方法,该方法不会立即返回.
Inside a thread I want to call a method from a boost::python
based object which will not return immediately.
为此,我将对象/方法包装如下:
To do so I wrap the object/method like this:
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!!
只要我之前运行一些代码 my_cpp_object.non_terminating_fn()
,一切就可以正常工作.如果没有,.start()
的阻止方式将与直接调用.run()
的方式相同.
And everything works fine as long as I run some code before my_cpp_object.non_terminating_fn()
. If I don't, .start()
will block the same way as calling .run()
directly would.
仅在调用boost::python
函数之前打印一行是不够的,但是例如打印两行或调用time.sleep()
会使start()
立即按预期返回.
Printing just a line before calling the boost::python
function is not enough, but e.g. printing two lines or calling time.sleep()
makes start()
return immediately as expected.
您能解释这种行为吗?我该如何避免这种情况(除了在调用boost::python
函数之前调用sleep()
之外)?
Can you explain this behavior? How would I avoid this (apart from calling sleep()
before calling a boost::python
function)?
推荐答案
此行为(就像在大多数情况下,您相信解释器/编译器中的错误)不是Python中的错误,而是竞赛条件涵盖了由于Python GIL 而引起的期望行为(还讨论了
This behavior is (as in most cases when you believe in a bug in an interpreter/compiler) not a bug in Python but a race condition covering the behavior you have to expect because of the Python GIL (also discussed here).
非Python函数my_cpp_object.non_terminating_fn()
一旦启动,直到返回GIL并释放GIL,并阻止解释器执行任何其他命令.
As soon as the non-Python function my_cpp_object.non_terminating_fn()
has been started the GIL doesn't get released until it returns and keeps the interpreter from executing any other command.
所以time.sleep(1)
还是无济于事,因为my_cpp_object.non_terminating_fn()
之后的代码要等到GIL释放后才能执行.
So time.sleep(1)
doesn't help here anyway because the code following my_cpp_object.non_terminating_fn()
would not be executed until the GIL gets released.
对于boost::python
,当然,如果您可以修改C /C ++部分,则可以按照此处.
In case of boost::python
and of course in case you can modify the C/C++ part you can release the GIL manually as described here.
一个小例子(来自上面的链接)可能看起来像这样(在boost :: python包装器代码中)
A small example (from the link above) could look like this (in the boost::python wrapper code)
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();
}
这篇关于Python的错误? threading.Thread.start()并不总是返回的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!