如何从 subprocess.Popen.stdout 读取所有可用数据(非阻塞)?

2022-01-18 00:00:00 python subprocess

问题描述

我需要一种方法来读取 Popen 创建的流中所有当前可用的字符,或者找出缓冲区中剩余的字符数.

I need a way to either read all currently available characters in stream created by Popen or to find out how many characters are left in the buffer.

背景:我想用 Python 远程控制一个交互式应用程序.到目前为止,我使用 Popen 创建了一个新的子进程:

Backround: I want to remote control an interactive application in Python. So far I used Popen to create a new subprocess:

process=subprocess.Popen(["python"],shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE, cwd=workingDir)

(我不是真的开始python,但实际的交互界面是相似的.)目前我读取了 1 个字节,直到我检测到进程已到达命令提示符:

(I'm not really starting python, but the actual interactive interface is similar.) At the moment I read 1 byte until I detect that the process has reached the command prompt:

output = ""
while output[-6:]!="SCIP> ":
    output += process.stdout.read(1)
    sys.stdout.write(output[-1])
return output

然后我通过 process.stdin.write("command ") 开始一个冗长的计算.我的问题是,我无法检查计算是否完成,因为我无法检查流中的最后一个字符是否是提示符.read()read(n) 阻塞我的线程,直到它到达 EOF,它永远不会,因为交互式程序在被告知之前不会结束.以上述循环的方式寻找提示也行不通,因为提示只会在计算之后出现.

Then I start a lengthy computation via process.stdin.write("command "). My problem is, that I cannot check whether the computation has finished or not, because I cannot check, whether the last characters in the stream are the prompt or not. read() or read(n) blocks my thread until it reaches EOF, which it never will, because the interactive program will not end until it is told to. Looking for the prompt in the way the above loop does won't work either, because the prompt will only occur after the computation.

理想的解决方案是让我从流中读取所有可用字符,如果没有可读取的内容,则立即返回一个空字符串.

The ideal solution would allow me to read all available character from the stream and immediately return an empty string, if there is nothing to read.


解决方案

四处寻找这个非常好的解决方案

Poking around I found this really nice solution

持久python子进程

通过使用 fcntl 将子进程管道上的文件属性设置为非阻塞模式,从而避免了阻塞问题,无需辅助线程或轮询.我可能遗漏了一些东西,但它解决了我的交互式过程控制问题.

which avoids the blocking issue all together by using fcntl to set file attributes on the subprocess pipes to non-blocking mode, no auxiliary threads or polling required. I could be missing something but it has solved my interactive process control problem.

相关文章