了解Popen.communicate

Bla*_*Hat 56 python subprocess communicate

我有一个名为的脚本1st.py,它创建了一个REPL(read-eval-print-loop):

print "Something to print"
while True:
    r = raw_input()
    if r == 'n':
        print "exiting"
        break
    else:
        print "continuing"
Run Code Online (Sandbox Code Playgroud)

然后我1st.py使用以下代码启动:

p = subprocess.Popen(["python","1st.py"], stdin=PIPE, stdout=PIPE)
Run Code Online (Sandbox Code Playgroud)

然后尝试了这个:

print p.communicate()[0]
Run Code Online (Sandbox Code Playgroud)

它失败了,提供了这个追溯:

Traceback (most recent call last):
  File "1st.py", line 3, in <module>
    r = raw_input()
EOFError: EOF when reading a line
Run Code Online (Sandbox Code Playgroud)

你能解释一下这里发生了什么吗?当我使用时p.stdout.read(),它会永远挂起.

jfs*_*jfs 53

.communicate() 写入输入(在这种情况下没有输入,因此它只关闭子进程'stdin以指示子进程没有更多输入),读取所有输出,并等待子进程退出.

在子进程中引发异常EOFError raw_input()(它预期数据但得到EOF(无数据)).

p.stdout.read()永远挂起,因为它试图在子进程等待导致死锁的input()的同时读取子进程的所有输出raw_input().

为了避免死锁,您需要异步读/写(例如,通过使用线程或选择)或确切地知道读/写的时间和数量,例如:

from subprocess import PIPE, Popen

p = Popen(["python", "-u", "1st.py"], stdin=PIPE, stdout=PIPE, bufsize=1)
print p.stdout.readline(), # read the first line
for i in range(10): # repeat several times to show that it works
    print >>p.stdin, i # write input
    p.stdin.flush() # not necessary in this case
    print p.stdout.readline(), # read output

print p.communicate("n\n")[0], # signal the child to exit,
                               # read the rest of the output, 
                               # wait for the child to exit
Run Code Online (Sandbox Code Playgroud)

注意:如果读/写不同步,它是一个非常脆弱的代码; 它陷入僵局.

谨防块缓冲问题(这里通过使用"-u"标志来解决,该标志关闭stdin的缓冲,孩子中的 stdout).

bufsize=1使管道在父端进行线缓冲.

  • 你能告诉我 print &gt;&gt;p.stdin,i 和 p.stdin.write(i) 有什么区别吗 (2认同)
  • 这里`print`是`p.stdin.write(str(i)+"\n"); p.stdin.flush()`。 (2认同)
  • 我想不断地谈论一个进程,不断地向它发送命令并不断地接收它的响应。但这个过程始终存在。如何做到这一点? (2认同)

Use*_*ser 20

不要使用通信(输入="").它将输入写入进程,关闭其stdin,然后读取所有输出.

像这样做:

p=subprocess.Popen(["python","1st.py"],stdin=PIPE,stdout=PIPE)

# get output from process "Something to print"
one_line_output = p.stdout.readline()

# write 'a line\n' to the process
p.stdin.write('a line\n')

# get output from process "not time to break"
one_line_output = p.stdout.readline() 

# write "n\n" to that process for if r=='n':
p.stdin.write('n\n') 

# read the last output from the process  "Exiting"
one_line_output = p.stdout.readline()
Run Code Online (Sandbox Code Playgroud)

你要做什么来删除错误:

all_the_process_will_tell_you = p.communicate('all you will ever say to this process\nn\n')[0]
Run Code Online (Sandbox Code Playgroud)

但是,由于通信关闭了stdout和,stdin并且stderr在您调用通信后无法读取或写入.