process.stdout.readline()挂起.如何正确使用?

Apo*_*tus 4 python subprocess stdout

我想重复发送处理标准输入的请求,并从标准输出接收响应,而不需要subprocess多次调用.我可以实现一次性请求 - 响应迭代,p.communicate但不要调用subprocess我需要使用的多次:process.stdout.readline()挂起.如何正确使用?我使用Python 2.7 64位,Windows 7.在此先感谢.

main.py:

import subprocess
p = subprocess.Popen(['python','subproc.py'],stdin=subprocess.PIPE,stdout=subprocess.PIPE)

while True:
    s=raw_input('Enter message:')
    p.stdin.write(s)
    p.stdin.flush()
    response = p.stdout.readline()
    if response!= '':
        print "Process response:", response
    else:
        break
Run Code Online (Sandbox Code Playgroud)

subproc.py:

from __future__ import division
import pyximport
s=raw_input()
print 'Input=',s
Run Code Online (Sandbox Code Playgroud)

dan*_*ano 7

为了实现这一目标,您可以进行一些小的调整.首先是使用该-u选项禁用子缓冲输出.第二种是将换行符与用户输入的消息一起发送到子进程,以便子进程中的raw_input呼叫完成.

main.py

import subprocess

# We use the -u option to tell Python to use unbuffered output
p = subprocess.Popen(['python','-u', 'subproc.py'],
                     stdin=subprocess.PIPE,
                     stdout=subprocess.PIPE)

while True:
    s = raw_input('Enter message:')
    p.stdin.write(s + "\n")  # Include '\n'
    p.stdin.flush()
    response = p.stdout.readline()
    if response != '': 
        print "Process response:", response
    else:
        break
Run Code Online (Sandbox Code Playgroud)

您还应该将子进程包装在无限循环中,否则在发送第一条消息后会出现问题:

subproc.py:

while True:
    s = raw_input()
    print 'Input=',s
Run Code Online (Sandbox Code Playgroud)

输出:

dan@dantop:~$ ./main.py 
Enter message:asdf
Process response: Input= asdf

Enter message:asdf
Process response: Input= asdf

Enter message:blah blah
Process response: Input= blah blah

Enter message:ok
Process response: Input= ok
Run Code Online (Sandbox Code Playgroud)


Joh*_*ger 5

假设子进程将立即获取您发送到其标准输入的完整数据是不安全的,因为缓冲区可能会妨碍。如果您必须保持文件打开以进行进一步输出,那么您至少应该调用它的flush()方法。

此外,假设子进程的输出将立即可供您阅读也是不安全的。如果它不刷新(或关闭)其输出流,则 EOL 可能会被缓冲,如果您不采取任何措施提示子进程进一步采取行动,那么您readline()可能会永远等待。但是你的程序就不能做任何事情,因为它被困在readline(). 如果子进程是为此构建的,那么您可能会使其正常工作,但否则您需要使用更安全的方法,例如subprocess.communicate().

communicate()正如您所观察到的,在同一个子进程上调用多次是行不通的。正如您从其文档中所期望的那样:它读取所有输出直到文件末尾,并等待子进程终止。要在此模式下发送多个输入,请构建一个包含所有输入的字符串,将其传递给communicate()然后读取所有答案。

或者,如果您确实需要在写入和读取之间交替,并且您的子进程没有专门为此设计的工具,那么在单独的线程中进行读取和写入会更安全,而不需要假设写入和读取完美地交错。


小智 -5

您需要用于communicate与子流程交互(https://docs.python.org/2/library/subprocess.html#subprocess.Popen.communicate)。这是主要代码的更新版本:

import subprocess
p = subprocess.Popen(['python','subproc.py'],stdin=subprocess.PIPE,stdout=subprocess.PIPE)

while True:
    s = raw_input('Enter message:')
    response, _ = p.communicate(s)
    if response!= '':
        print "Process response:", response
    else:
        break
Run Code Online (Sandbox Code Playgroud)

您还必须小心,当主代码中有循环时,您的子过程代码仅运行一次。只有第一次迭代才能正确接收响应,第二次communicate调用将引发异常,因为stdin届时子流程的文件将被关闭。

  • 使用 p.communicate() 的问题是,除了通过 stdin 发送数据之外,它还会阻塞,直到子进程完成。OP 希望能够重复发送数据到 stdin,而不必重新启动子进程。 (5认同)