我有以下脚本:
#!/usr/bin/python
while True:
x = raw_input()
print x[::-1]
我是从ipython
调用它:
In [5]: p = Popen('./script.py', stdin=PIPE)
In [6]: p.stdin.write('abc\n')
cba
它工作正常。
然而,当我这样做时:
In [7]: p = Popen('./script.py', stdin=PIPE, stdout=PIPE)
In [8]: p.stdin.write('abc\n')
In [9]: p.stdout.read()
解释器挂起了。我究竟做错了什么?我希望能够多次写入和读取另一个进程,将一些任务传递给此进程。我需要做些什么不同的事情?
编辑1
如果我使用communicate
,我明白了:
In [7]: p = Popen('./script.py', stdin=PIPE, stdout=PIPE)
In [8]: p.communicate('abc\n')
Traceback (most recent call last):
File "./script.py", line 4, in <module>
x = raw_input()
EOFError: EOF when reading a line
Out[8]: ('cba\n', None)
编辑2
我试着冲洗:
#!/usr/bin/python
import sys
while True:
x = raw_input()
print x[::-1]
sys.stdout.flush()
在这里:
In [5]: from subprocess import PIPE, Popen
In [6]: p = Popen('./script.py', stdin=PIPE, stdout=PIPE)
In [7]: p.stdin.write('abc')
In [8]: p.stdin.flush()
In [9]: p.stdout.read()
但它又挂了。
答案 0 :(得分:15)
我相信这里有两个问题:
1)您的父脚本调用p.stdout.read()
,它将读取所有数据,直到文件结束。但是,您的子脚本在无限循环中运行,因此文件末尾永远不会发生。可能你想要p.stdout.readline()
?
2)在交互模式下,大多数程序一次只缓冲一行。从另一个程序运行时,它们可以缓冲更多。缓冲在许多情况下提高了效率,但是当两个程序需要交互式通信时会导致问题。
p.stdin.write('abc\n')
之后添加:
p.stdin.flush()
在您的子流程脚本中,在print x[::-1]
之后在循环中添加以下内容:
sys.stdout.flush()
(和import sys
位于顶部)
答案 1 :(得分:3)
子流程方法check_output对此非常有用:
output = subprocess.check_output('./script.py')
输出将是该过程的标准输出。如果你也需要stderr:
output = subprocess.check_output('./script.py', stderr=subprocess.STDOUT)
由于您避免直接管理管道,因此可能会绕过您的问题。
答案 2 :(得分:3)
如果您想将多行传递给script.py
,那么您需要同时读/写:
#!/usr/bin/env python
import sys
from subprocess import PIPE, Popen
from threading import Thread
def print_output(out, ntrim=80):
for line in out:
print len(line)
if len(line) > ntrim: # truncate long output
line = line[:ntrim-2]+'..'
print line.rstrip()
if __name__=="__main__":
p = Popen(['python', 'script.py'], stdin=PIPE, stdout=PIPE)
Thread(target=print_output, args=(p.stdout,)).start()
for s in ['abc', 'def', 'ab'*10**7, 'ghi']:
print >>p.stdin, s
p.stdin.close()
sys.exit(p.wait()) #NOTE: read http://docs.python.org/library/subprocess.html#subprocess.Popen.wait
4 cba 4 fed 20000001 bababababababababababababababababababababababababababababababababababababababa.. 4 ihg
script.py
:
#!/usr/bin/env python
"""Print reverse lines."""
while True:
try: x = raw_input()
except EOFError:
break # no more input
else:
print x[::-1]
或者
#!/usr/bin/env python
"""Print reverse lines."""
import sys
for line in sys.stdin:
print line.rstrip()[::-1]
或者
#!/usr/bin/env python
"""Print reverse lines."""
import fileinput
for line in fileinput.input(): # accept files specified as command line arguments
print line.rstrip()[::-1]
答案 3 :(得分:1)
你可能会绊倒Python的输出缓冲。以下是python --help
对此的评论。
-u : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x
see man page for details on internal buffering relating to '-u'
答案 4 :(得分:1)
当你写到p.stdin时,请关闭它:p.stdin.close()
答案 5 :(得分:-3)
使用communicate()
代替.stdout.read()
。
示例:
from subprocess import Popen, PIPE
p = Popen('./script.py', stdin=PIPE, stdout=PIPE, stderr=PIPE)
input = 'abc\n'
stdout, stderr = p.communicate(input)
此推荐来自Popen objects中的subprocess documentation部分:
警告:使用communic()而不是.stdin.write,.stdout.read或.stderr.read 避免由于任何其他OS管道缓冲区填满和阻塞导致的死锁 儿童过程。