在子进程中使用stdin

7 投票
4 回答
7123 浏览
提问于 2025-04-17 02:42

我有一个程序,在“主”进程中,我启动了一个新的进程对象。这个新进程的目的是从 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模块。不过,我不太确定在更复杂的系统中这个方法是否可靠。

撰写回答