从Python进程中的stdin读取?

时间:2015-06-01 04:07:49

标签: python process stdin

我试图从Python Process对象内部读取sys.stdin,但我一直在关闭文件中获得" ValueError:I / O操作"结果。这是一个简单的例子:

import sys
from multiprocessing import Process

def do_something(input_data):
    for x in input_data:
        print x


input=sys.stdin

p = Process(target=do_something, args=(input,))
p.start() 
p.join() #Wait for Process to complete 

以上脚本始终失败:

Traceback (most recent call last):
  File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/process.py", line 258, in _bootstrap
    self.run()
  File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/process.py", line 114, in run
    self._target(*self._args, **self._kwargs)
  File "example.py", line 6, in do_something
    for x in input_data:
ValueError: I/O operation on closed file

当然,在不使用进程的情况下调用do_something(input)可以正常工作。创建一个Pipe()对象似乎有所帮助 - 我可以将stdin的内容写入Pipe并从进程中以字符串形式获取结果 - 但实际上我需要输入到类似文件的表单以进行某些下游操作。我可以将内容转储到文件中并从Process中重新读取它,但这看起来非常笨拙,特别是如果stdin非常大。是否有一些简单的方法可以从进程内的sys.stdin中读取?

2 个答案:

答案 0 :(得分:2)

这是因为在启动流程之前,stdin已关闭。否则可能会发生父进程和子进程(或多个子进程)尝试从同一个stdin读取,这是一个坏主意。

在子流程中,sys.stdin实际上已重定向到/dev/null

from multiprocessing import Process
import sys

def test(*args):
    print(args)
    print(sys.stdin, sys.stdin.fileno())

if __name__ == '__main__':
    p = Process(target=test, args=(sys.stdin,))
    p.start()
    p.join()

应该打印类似的东西:

(<closed file '<stdin>', mode 'r' at 0x7f3b4564b0c0>,)
(<open file '/dev/null', mode 'r' at 0x7f3b43a9e0c0>, 3)

这里传递的参数是对已关闭文件对象的引用,尝试使用它会引发您看到的错误。

您可以通过在父级sys.stdin.fileno()上使用os.dup()来解决此问题,并将返回的文件描述符副本作为参数传递给子级,然后您可以使用os.fdopen()来与之合作。

更干净的解决方案可能是使用pass it to the child读取父进程中的输入和multiprocessing.Queue

答案 1 :(得分:0)

您必须在某个时候关闭您尝试写入的文件。检查您的代码并尝试删除所有关闭文件的行( fileVariableName .close())并查看它是否有效。如果是,则逐个重新添加它们以找到问题。一旦找到导致问题的行,请尝试将其进一步移入程序(稍后调用),看看是否能解决问题。

编辑:更改

def do_something(input_data):
    for x in input_data:
        print x

def do_something():
    for x in sys.stdin:
        print x

并摆脱input = sys.stdin