Python 子进程管道块



由于某些原因,在此示例中,consumer似乎被阻止了(因为它正在等待EOF?但是管道的写入端应该已经关闭。

import os, subprocess, threading
(r, w) = os.pipe()
def producer():
print '--producer started'
subprocess.Popen(['echo', '123'], stdout=w).wait()
print '--producer finished'
os.close(w)
print '--write pipe closed'
def consumer():
print '--receiver started'
subprocess.Popen(['cat'], stdin=r).wait()
print '--receiver finished'
os.close(r)
print '--read pipe closed'
threading.Thread(target=producer).start()
threading.Thread(target=consumer).start()

这里的问题是所有进程都继承所有打开的文件描述符,并且当所有进程中的写入端已关闭时,管道的读取端只会有一个 EOF。因为cat进程本身使写入端保持打开状态,所以主进程中的调用os.close(w)是不够的。

对于这种情况,Popen()具有close_fds参数,当设置为True时,将导致除用于 stdin、stderr 和 stout 的文件描述符之外的所有打开的文件描述符在创建子流程后立即关闭。如果这样做,您的示例应按预期工作。

在python2上close_fds=False是默认值,在python3中将其更改为close_fds=True,此外,由于python3.4文件描述器应该继承需要使用os.set_inheritable()显式标记为可继承。这减少了这种问题。

你的程序永远不会退出的原因是你在等待猫,除了猫在等待永远不会到来的EOF。

当您调用subprocess.Popen(['cat'], stdin=r).wait()时,它会从文件描述符中读取并将其打印到 stdout,因为您没有重定向 stdout。 这就是为什么您仍然在屏幕上看到"123"的原因。

请考虑以下任一选项: 使用队列:

import threading
from Queue import Queue
q= Queue()
def producer():
print '--producer started'
q.put('123')
print '--producer finished'
def consumer():
print '--receiver started'
print q.get()
print '--receiver finished'
threading.Thread(target=producer).start()
threading.Thread(target=consumer).start()

或使用os.pipe但改用readwrite

import os, subprocess, threading
(r, w) = os.pipe()
def producer():
print '--producer started'
os.write(w, '123')
print '--producer finished'
os.close(w)
print '--write pipe closed'
def consumer():
print '--receiver started'
print os.read(r, 3)
print '--receiver finished'
os.close(r)
print '--read pipe closed'
threading.Thread(target=producer).start()
threading.Thread(target=consumer).start()

最新更新