有没有办法通过&#st; stdin'作为python中另一个进程的参数?

时间:2012-01-23 18:50:36

标签: python multiprocessing stdin

我正在尝试创建一个使用python的多处理模块的脚本。脚本(让我们称之为myscript.py)将从另一个带有管道的脚本获取输入。

假设我像这样调用脚本;

$ python writer.py | python myscript.py 

这是代码;

// writer.py
import time, sys

def main():
    while True:
        print "test"
        sys.stdout.flush()
        time.sleep(1)

main()

//myscript.py
def get_input():
    while True:
        text = sys.stdin.readline()
        print "hello " + text
        time.sleep(3)

if __name__ == '__main__':        
    p1 = Process(target=get_input, args=())
    p1.start()

这显然不起作用,因为sys.stdin对象对于主进程和p1是不同的。所以我试过这个来解决它,

//myscript.py
def get_input(temp):
    while True:
        text = temp.readline()
        print "hello " + text
        time.sleep(3)

if __name__ == '__main__':        
    p1 = Process(target=get_input, args=(sys.stdin,))
    p1.start()

但我遇到了这个错误;

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 "in.py", line 12, in get_input
    text = temp.readline()
ValueError: I/O operation on closed file

所以,我猜主要的stdin文件已关闭,我无法从中读取。在这个结合处,我如何将main的stdin文件传递给另一个进程?如果无法传递stdin,我如何从另一个进程使用main的stdin?

更新 好的,我需要澄清我的问题,因为人们认为使用多处理并不是必需的。 像这样考虑myscript.py;

//myscript.py
def get_input():
    while True:
        text = sys.stdin.readline()
        print "hello " + text
        time.sleep(3)

def do_more_things():
    while True:
        #// some code here
        time.sleep(60*5)

if __name__ == '__main__':        
    p1 = Process(target=get_input, args=())
    p1.start()

    do_more_things()

所以,我真的需要与main函数(或其他子进程)并行运行get_input()函数。 对不起冲突,我有一个体面的英语,我想我不能清楚这个问题。如果你们能告诉我我是否可以在另一个进程中使用主进程STDIN对象,我将不胜感激。

提前感谢。

4 个答案:

答案 0 :(得分:9)

最简单的事情是交换get_input()do_more_things(),即在父流程中阅读sys.stdin

def get_input(stdin):
    for line in iter(stdin.readline, ''):
        print("hello", line, end='')
    stdin.close()

if __name__ == '__main__':
    p1 = mp.Process(target=do_more_things)
    p1.start()
    get_input(sys.stdin)

下一个最好的方法是使用Thread()而不是Process() get_input()

if __name__ == '__main__':
    t = Thread(target=get_input, args=(sys.stdin,))
    t.start()
    do_more_things()

如果上述方法无效,您可以尝试os.dup()

newstdin = os.fdopen(os.dup(sys.stdin.fileno()))
try: 
   p = Process(target=get_input, args=(newstdin,))
   p.start()    
finally:
   newstdin.close() # close in the parent
do_more_things()

答案 1 :(得分:2)

使用多处理模块创建的每个新进程都有自己的PID,因此它是自己的标准输入设备和输出设备,即使它们都写入同一个终端,因此需要锁定。

您已经通过将内容分成两个脚本并使用get_input()创建第三个进程来创建两个进程。如果是一个线程而不是一个进程,get_input可以读取标准输入。然后,不需要在阅读器中具有睡眠功能。

## reader.py
from threading import Thread
import sys

def get_input():
    text = sys.stdin.readline()
    while len(text) != 0:
        print 'hello ' + text
        text = sys.stdin.readline()

if __name__ == '__main__':
    thread = Thread(target=get_input)
    thread.start()
    thread.join()

答案 2 :(得分:2)

这只是部分答案 - 因为我不清楚问题的后续部分。

首先说你预计会调用你的脚本:

$ python writer.py | python myscript.py 

如果你要这样做,作者需要写标准输出和myscript需要从标准输入读取。第二个脚本看起来像这样:

def get_input():
    while True:
        text = sys.stdin.readline()
        print "hello " + text
        time.sleep(3)
if __name__ == '__main__':    
    get_input()

不需要multiprocessing.Process对象......你已经从命令行启动了两个进程 - 你正在使用shell将它们与(匿名)管道(“|”字符连接起来) )将第一个脚本的标准输出连接到第二个脚本的标准输入。

Process对象的要点是从第一个进程管理第二个进程的启动。你需要定义一个过程;然后启动它 - 然后你可能要等到它在退出第一个进程之前终止...(在p1.start()之后调用p1.join()就足够了。)

如果你想在python控制下的一对进程之间进行通信,你可能想要使用multiprocess.Pipe对象来执行此操作。然后,您可以通过读取和写入Pipe对象而不是标准输入和标准输出,轻松地在初始和下级生成的进程之间进行通信。如果你真的想重新引导标准输入和标准输出,这可能是通过搞乱低级文件描述符和/或覆盖/替换sys.stdin和sys.stdout对象来实现的......但是,我怀疑,你可能不想(或不需要)这样做。

答案 3 :(得分:1)

要在输入中阅读管道,请使用fileinput

myscript.py

import fileinput

if __name__ == '__main__':
    for line in fileinput.input():
        #do stuff here
        process_line(line)