【问题标题】:process.stdout.readline() hangs. How to use it properly?process.stdout.readline() 挂起。如何正确使用?
【发布时间】:2014-08-29 16:13:31
【问题描述】:

我想重复发送请求以处理标准输入并接收来自标准输出的响应而不多次调用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

subproc.py

from __future__ import division
import pyximport
s=raw_input()
print 'Input=',s

【问题讨论】:

    标签: python subprocess stdout


    【解决方案1】:

    您可以进行一些小调整以使其正常工作。首先是使用-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
    

    您还应该将子进程包裹在一个无限循环中,否则在发送第一条消息后事情会中断:

    subproc.py

    while True:
        s = raw_input()
        print 'Input=',s
    

    输出:

    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
    

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

      • 感谢您指出flush thingy,当您只是考虑与另一个程序进行通信并且我调试了我的脚本的所有其他方面试图弄清楚我去了哪里时,这很容易被忽视错误的。这是一个非常讨厌的错误来源,因为部分消息正确到达,而部分消息仍然挂在缓冲区中。
      【解决方案3】:

      您需要使用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
      

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

      【讨论】:

      • 使用p.communicate()的问题是除了通过stdin发送数据外,还会阻塞直到子进程完成。 OP 希望能够重复发送数据到标准输入,而不必重新启动子进程。
      猜你喜欢
      • 2012-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-25
      相关资源
      最近更新 更多