我正在尝试创建一个使用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对象,我将不胜感激。
提前感谢。
答案 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)