本文介绍了从 Windows 上的 subprocess.stdout 实时读取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

强调一下,问题在于实时读取,而不是非阻塞读取.之前有人问过,例如subprocess.Popen.stdout - 实时读取标准输出-时间(再次).但没有提出令人满意的解决方案.

To emphasize, the problem is real time read instead of non-blocking read. It has been asked before, e.g. subprocess.Popen.stdout - reading stdout in real-time (again). But no satisfactory solution has been proposed.

例如,下面的代码尝试模拟python shell.

As an example, the following code tries to simulate the python shell.

import subprocess

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

while True:
    line = input('>>> ')
    p.stdin.write(line.encode())
    print('>>> ', p.stdout.read().decode())

但是,从p.stdout读取时会被阻塞.找了一圈,发现了以下两种可能的方案.

However, it would be blocked when reading from p.stdout. After searching around, I found the following two possible soutions.

  1. 使用 fctrlO_NONBLOCK
  2. 使用threadqueue

虽然第一个方案可以工作并且只能在 linux 上工作,但第二个方案只是将阻塞读取转换为非阻塞读取,即我无法获得子进程的实时输出.例如,如果我输入 'print("hello")',我将不会从 p.stdout 使用第二种解决方案得到任何信息.

Whereas the 1st soution may work and only work on linux, the 2nd soution just turn blocking read to non-blocking read, i.e. I cannot get real time output of the subprocess. For example, if I input 'print("hello")', I will get nothing from p.stdout using 2nd solution.

也许有人会建议 p.communite.不幸的是,它不适合这种情况,因为它会按照此处所述关闭标准输入.

Perhaps, someone would suggest p.communite. Unfortunately, it is not suitable in this case, since it would close stdin as described here.

那么,有没有针对 Windows 的解决方案?

So, is there any solutions for Windows?

已编辑:即使 -u 已打开并且 p.stdout.read 被替换为 p.stdout.readline,问题依旧.

Edited: Even if -u is turned on and p.stdout.read is replaced with p.stdout.readline, the problem still exists.

import subprocess

p = subprocess.Popen(['python', '-u'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)

while True:
    line = input('>>> ')
    p.stdin.write(line.encode())
    p.stdin.flush()
    print('>>> ', p.stdout.readline().decode())

解决方案:以下是基于 J.F. Sebastian 的回答和评论的最终代码.

Solution: The following is the final code based on J.F. Sebastian's answer and comments.

from subprocess import Popen, PIPE, STDOUT

with Popen(
        ['python', '-i', '-q'],
        stdin=PIPE, stdout=PIPE, stderr=STDOUT,
        bufsize=0
    ) as process:
    while True:
        line = input('>>> ')
        if not line:
            break
        process.stdin.write((line+'\n').encode())
        print(process.stdout.readline().decode(), end='')

需要注意的是,当命令触发无输出时,程序会挂起.

It should be noted that the program would hang when the command triggers no output.

推荐答案

这是一个完整的工作示例,它以交互方式使用子流程:

Here's a complete working example that uses a subprocess interactively:

#!/usr/bin/env python3
import sys
from subprocess import Popen, PIPE, DEVNULL

with Popen([sys.executable, '-i'], stdin=PIPE, stdout=PIPE, stderr=DEVNULL,
           universal_newlines=True) as process:
    for i in range(10):
        print("{}**2".format(i), file=process.stdin, flush=True)
        square = process.stdout.readline()
        print(square, end='')

这是另一个例子:如何运行[sys.executable, '-u', 'test.py'] 交互.

Here's another example: how to run [sys.executable, '-u', 'test.py'] interactively.

这篇关于从 Windows 上的 subprocess.stdout 实时读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-11 21:31