我一直在尝试使用子进程对 subprocess.PIPE 进行故障排除,但没有成功。
我试图将命令传递给始终运行的进程并接收结果,而不必每次都关闭/打开进程。
这是主要的启动代码:
启动器.py:
import subprocess
import time
command = ['python', 'listener.py']
process = subprocess.Popen(
command, bufsize=0,
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
)
# simulates sending a new command every 10 seconds
for x in range(1,10):
process.stdin.write(b'print\r\n')
process.stdin.flush()
time.sleep(10)
监听器.py:
import sys
file = open('log.txt', 'w+')
while True:
file.write(sys.stdin.read(1))
file.close()
这已被简化以显示相关部分。最后,我将让线程监听 stdout 和 stderr,但现在我正在尝试解决基础问题。
我期望发生的情况:对于 launcher.py 中的每个循环,listener.py 中的 file.write() 都会写入。 相反会发生什么:当循环关闭并且程序终止时,或者我对脚本执行 SIGTERM/CTRL-C 时,所有内容都会写入。
我在 Windows 8 Python 3.4 中运行它。
这几乎就像标准输入缓冲,直到进程关闭然后它通过。我设置了 buffsize=0,并且我正在冲洗,所以这对我来说没有意义。我认为其中之一就足够了。
子进程在不同的进程中运行,因此启动器中的 sleep 应该不会对子进程产生影响。
有人知道为什么会被阻止吗?
更新 1: 从控制台运行以下代码 (python.exe stdinreader.py) 也可以看到相同的行为
也就是说,当您在程序运行时在控制台中键入内容时,不会向文件写入任何内容。
stdinreader.py:
import sys
import os
file = open('log.txt', 'w+b')
while True:
file.write(sys.stdin.read(1))
file.close()
在 file.write() 之前添加 file.flush() 可以解决这个问题,但这对我的子进程没有帮助,因为我无法控制子进程如何刷新(这将是我的返回 subprocess.PIPE )。也许如果我用 open('wb') 重新初始化该 PIPE,它就不会缓冲。我会努力的。
更新 2: 我似乎已将此问题隔离到被调用的子进程,该子进程在写入标准输出后不会刷新。
有什么办法可以在不修改子进程的情况下强制刷新父级和子级之间的标准输出管道吗?子进程是使用 args ['-script 运行的 magick.exe (imagemagick 7) ,'-']。从子进程的角度来看,它有一个标准输出对象<_io.TextIOWrapper name='' mode='w'encoding='cp1252'>。我猜子进程只会在初始化时打开默认的 stdout 对象,我们无法真正控制它是否缓冲。
奇怪的是,向子进程传递普通的 sys.stdout 对象而不是 subprocess.PIPE 并不需要子进程在写入后执行 .flush() 。
最佳答案
程序的运行方式有所不同,具体取决于它们是从控制台运行还是通过管道运行。如果控制台(Python 进程可以使用 os.stdin.isatty() 检查),stdout 数据是行缓冲的,您可以立即看到数据。如果管道,标准输出数据是 block 缓冲的,并且只有在堆积了相当多的数据或程序刷新管道时您才能看到数据。
当你想抓取程序输出时,你必须使用管道,并且程序以缓冲模式运行。在 Linux 上,您可以通过创建假控制台(伪 tty、pty...)来欺骗程序。 pty 模块、pexpect 和其他模块可以做到这一点。
在 Windows 上,我不知道有什么方法可以让它工作。如果您控制正在运行的程序,请经常刷新它。否则,盯着 Windows Logo 是徒劳的。如果您希望提前结束,您甚至可以在下次相亲时提及这个问题。但我想不出更多的事情了。
(如果有人知道修复方法,我很想听听。我见过一些尝试打开 Windows 控制台并屏幕抓取它的代码,但这些解决方案不断丢失数据。如果有的话,它应该可以工作某处有一个环回字符设备)。
关于python - 子进程 stdin PIPE 在程序终止之前不会返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25965332/