在子进程中使用stdin
我有一个程序,在“主”进程中,我启动了一个新的进程对象。这个新进程的目的是从 stdin
中读取行,并把这些行添加到一个 Queue
对象里。
简单来说,系统的基本设置是有一个“获取命令”的进程,用户可以在这里输入命令或查询。我需要把这些查询传递给其他在不同进程中运行的子系统。我打算通过一个 multiprocessing.Queue
来共享这些查询,这样其他系统就可以从中读取。
我现在的代码(专注于获取命令/查询)基本上是:
def sub_proc(q):
some_str = ""
while True:
some_str = raw_input("> ")
if some_str.lower() == "quit":
return
q.put_nowait(some_str)
if __name__ == "__main__":
q = Queue()
qproc = Process(target=sub_proc, args=(q,))
qproc.start()
qproc.join()
# now at this point q should contain all the strings entered by the user
问题是我遇到了:
Process Process-1:
Traceback (most recent call last):
File "/usr/lib/python2.7/multiprocessing/process.py", line 258, in _bootstrap
self.run()
File "/usr/lib/python2.7/multiprocessing/process.py", line 114, in run
self._target(*self._args, **self._kwargs)
File "/home/blah/blah/blah/blah.py", line 325, in sub_proc
some_str = raw_input("> ")
File "/randompathhere/eclipse/plugins/org.python.pydev_2.1.0.2011052613/PySrc/pydev_sitecustomize/sitecustomize.py", line 181, in raw_input
ret = original_raw_input(prompt)
EOFError: EOF when reading a line
该怎么做呢?
4 个回答
1
如果你不想把标准输入(stdin)传给目标进程的函数,就像@Ashelly的回答那样,或者你需要对很多不同的进程这样做,你可以通过multiprocessing.Pool
的初始化参数来实现:
import os, sys, multiprocessing
def square(num=None):
if not num:
num = int(raw_input('square what? '))
return num ** 2
def initialize(fd):
sys.stdin = os.fdopen(fd)
initargs = [sys.stdin.fileno()]
pool = multiprocessing.Pool(initializer=initialize, initargs=initargs)
pool.apply(square, [3])
pool.apply(square)
上面的例子会先打印数字9,然后会提示你输入,接着会输出你输入数字的平方。
不过要小心,不要让多个子进程同时从同一个输入源读取数据,否则可能会变得... 有点混乱。
3
简单来说,主程序和你的第二个程序并不共享相同的输入流。
from multiprocessing import Process, Queue
import sys
def sub_proc():
print sys.stdin.fileno()
if __name__ == "__main__":
print sys.stdin.fileno()
qproc = Process(target=sub_proc)
qproc.start()
qproc.join()
运行这个,你应该会看到 sys.stdin.fileno() 的结果是两个不同的值。
不过,这样并不能解决你的问题。你到底想要做什么呢?
12
我通过把原来的标准输入文件描述符传给子进程,然后在子进程里重新打开它,解决了一个类似的问题。
def sub_proc(q,fileno):
sys.stdin = os.fdopen(fileno) #open stdin in this process
some_str = ""
while True:
some_str = raw_input("> ")
if some_str.lower() == "quit":
return
q.put_nowait(some_str)
if __name__ == "__main__":
q = Queue()
fn = sys.stdin.fileno() #get original file descriptor
qproc = Process(target=sub_proc, args=(q,fn))
qproc.start()
qproc.join()
这个方法在我比较简单的情况下有效。我甚至可以在重新打开的流上使用readline模块。不过,我不太确定在更复杂的系统中这个方法是否可靠。