Python的错误? threading.Thread.start()并不总是返回 [英] Bug in Python? threading.Thread.start() does not always return

查看:562
本文介绍了Python的错误? threading.Thread.start()并不总是返回的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个很小的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆