使用Python subprocess
库生成子进程后,我使用stderr
将子进程的消息传递给包含一些序列化数据的父进程。然后,我希望父级返回(通过stdin
)应用于此数据的函数的结果。
本质上,我在子进程中有一个函数,它执行如下操作:
sys.stderr.write("some stuff to write")
# some time later
some_var = sys.stdin.read()
但是,这样就完成了在等待stderr
输入时锁定父节点,所以我试着调用:
sys.stderr.flush()
os.fsync(sys.stderr.fileno())
然而,这不起作用。 os.fsync
执行后没有任何内容。此外,当我在父进程中调用proc.poll()
时,显示该子进程的返回码为1.
我该怎么做才能防止这种情况发生?我应该考虑另一种方法吗?
答案 0 :(得分:2)
我会考虑另一种方法。 您可以使用独立进程(multiprocessing.Process)并使用两个队列与其进行通信(multiprocessing.Queue),一个用于输入,另一个用于输出。 启动流程的示例:
import multiprocessing
def processWorker(input, result):
work = input.get()
print work
result.put(work*work)
input = multiprocessing.Queue()
result = multiprocessing.Queue()
p = multiprocessing.Process(target = processWorker, args = (input, result))
p.start()
input.put(2)
res = result.get(block = True)
print res
然后你可以再次迭代传递它。使用multiprocessing.Queue更加健壮,因为您不需要依赖stdout / err解析,也可以避免相关限制。 此外,您可以轻松管理更多子流程。
然后,您还可以设置您希望get调用等待多长时间的超时,例如:
import queue
try:
res = result.get(block = True, timeout = 10)
except Queue.Empty:
print error
答案 1 :(得分:1)
以下是如何在不彻底改变方法的情况下防止I / O死锁的方法。在孩子身上:
import os, fcntl
map(lambda f: fcntl.fcntl(f.fileno(), fcntl.F_SETFL, os.O_NONBLOCK),
(sys.stdin, sys.stdout, sys.stderr))
在父级中,对子级的管道文件描述符执行相同操作。然后,当您使用select.select()
进行通信时,您将不再拥有这些锁定。但是,您必须在写入之前使用select(),在尝试读/写时可能会收到EAGAIN
错误,并且根据您的应用程序逻辑,您可能无论如何都会有无限期的等待情况。
老实说,我建议您查看Twisted框架,该框架内置了子进程功能:http://twistedmatrix.com/documents/current/core/howto/process.html