Python 在线程中调用 pipe.communicate()

Posted

技术标签:

【中文标题】Python 在线程中调用 pipe.communicate()【英文标题】:Python calling pipe.communicate() in a thread 【发布时间】:2010-03-30 02:05:01 【问题描述】:

在 Mac OS X 10.6.2 上使用 Python 2.6.1,我遇到了以下问题:

我有一个线程进程(一个 Thread 类),每个线程都有一个管道(一个 subprocess.Popen),类似这样:

 from threading import Thread

 cmd = "some_cmd"

 class Worker(Thread):
    def run(self):
       pipe = Popen(cmd,
        stdin=PIPE,
        stdout=PIPE,
        stderr=PIPE)

       out, err = pipe.communicate("some data")

问题是 pipe.communicate() 代码被阻塞了。有趣的是,当我向父进程发送中断(例如Ctrl-CKeyboardInterrupt)时,它会解除阻塞。

有趣的是,当我使用class Worker(multiprocessing.Process) 时,代码运行良好。

任何关于为什么会阻塞 以及如何解决它的想法 - 将不胜感激。

谢谢。

【问题讨论】:

刚刚找到***.com/questions/984941/… - 但是我不确定修复是什么(还)! 看起来 Popen 可能不是线程安全的。非常有义务进行更正或澄清。在该主题上找到mail.python.org/pipermail/python-bugs-list/2007-August/…。 communicate() 应该被阻止。你的意思是它阻塞了整个程序,而不仅仅是它正在运行的线程?能否提供一个完整的示例程序? @Daniel Stutzbach:communicate 正在阻塞,即使进程确实(或应该)终止。我会尽快提出一个(非)工作示例。 @Daniel Stutzbach:因为这个问题,我放弃了并回到multiprocessing.Process(它没有阻止communicate)设计完全不同,所以我无法重现记忆中的测试用例。唉,这个问题的原因仍然是个谜,但我强烈怀疑这是因为 Popen 调用不是线程安全的,因为设计原样的唯一区别是它是一个 threading.Threadmultiprocessing.Process 相比。在之前的 communicate 被阻止(如果这是正确的词的话),但在后者中它按预期终止。 【参考方案1】:

如果您在主线程中调用sys.exit(),其他线程将在下一次机会时终止(在大多数操作系统上)。但是,如果它们处于阻塞调用中(例如communicate()),它们将等到阻塞调用完成后再终止。 Control-C 起作用是因为它会导致操作系统中断阻塞调用。

一般来说,最安全的方法是确保没有任何线程调用可能无限期阻塞的函数。不幸的是,这通常需要编写更多代码。

在您的特定情况下,您可以在调用通信之前将Popen 对象存储在全局set() 中,并在退出之前让主线程对它们中的每一个调用Popen.terminate()。这会导致子进程退出,communicate() 返回,线程退出。

您是否将线程设置为daemon 线程?

【讨论】:

【参考方案2】:

使用多线程多进程通常会导致问题,尤其是(但不限于)在基于 Unix 的系统上;我建议您避免将两者混为一谈。

【讨论】:

以上是关于Python 在线程中调用 pipe.communicate()的主要内容,如果未能解决你的问题,请参考以下文章

python 协程(单线程中的异步调用)(转廖雪峰老师python教程)

使用线程在python中调用多个c++函数

为啥 sys.exit() 在 Python 的线程内调用时不退出?

boost::python - 如何从 C++ 在自己的线程中调用 python 函数?

C++,多线程,线程中调用的函数能不能直接使用线程中定义的变量?

如何使用 pybind11 在 C++ 线程中调用 Python 函数作为回调