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-C
KeyboardInterrupt)时,它会解除阻塞。
有趣的是,当我使用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.Thread
与multiprocessing.Process
相比。在之前的 communicate
被阻止(如果这是正确的词的话),但在后者中它按预期终止。
【参考方案1】:
如果您在主线程中调用sys.exit()
,其他线程将在下一次机会时终止(在大多数操作系统上)。但是,如果它们处于阻塞调用中(例如communicate()),它们将等到阻塞调用完成后再终止。 Control-C 起作用是因为它会导致操作系统中断阻塞调用。
一般来说,最安全的方法是确保没有任何线程调用可能无限期阻塞的函数。不幸的是,这通常需要编写更多代码。
在您的特定情况下,您可以在调用通信之前将Popen
对象存储在全局set()
中,并在退出之前让主线程对它们中的每一个调用Popen.terminate()
。这会导致子进程退出,communicate()
返回,线程退出。
您是否将线程设置为daemon 线程?
【讨论】:
【参考方案2】:使用多线程和多进程通常会导致问题,尤其是(但不限于)在基于 Unix 的系统上;我建议您避免将两者混为一谈。
【讨论】:
以上是关于Python 在线程中调用 pipe.communicate()的主要内容,如果未能解决你的问题,请参考以下文章
python 协程(单线程中的异步调用)(转廖雪峰老师python教程)
为啥 sys.exit() 在 Python 的线程内调用时不退出?
boost::python - 如何从 C++ 在自己的线程中调用 python 函数?