我一直试图用subprocesses解决Subprocess.PIPE没有运气 .
我正在尝试将命令传递给始终正在运行的进程并接收结果,而不必每次都关闭/打开进程 .
这是主要的启动代码:
launcher.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)
listener.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中运行它 .
它几乎就像stdin缓冲,直到进程关闭然后它通过 . 我有buffsize = 0设置,我正在冲洗,所以这对我没有意义 . 我认为其中一个或另一个就足够了 .
子进程在不同的进程中运行,因此启动器中的sleep应该对子进程没有影响 .
有没有人有任何想法,为什么这是阻止?
Update 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,它就不会缓冲 . 我会尝试 .
Update 2: 我似乎已将此问题隔离到被调用的子进程,该进程在写入stdout后没有刷新 .
Is there anything I can do to force a flush on the stdout PIPE between parent and child without modifying the subprocess? 子进程是magick.exe(imagemagick 7)运行args ['-script, ' - ']. From the point of view of the subprocess it has a stdout object of <_io.TextIOWrapper name=' ' mode=' w ' encoding=' cp1252 '>. I guess the subprocess will just open the default stdout objects on initialization and we can' t真正控制它是否缓冲 .
奇怪的是,传递子进程的正常sys.stdout对象而不是subprocess.PIPE在写入后不需要子进程到.flush() .
3 回答
程序的运行方式不同,具体取决于它们是从控制台运行还是通过管道运行 . 如果控制台(python进程可以使用os.stdin.isatty()检查),stdout数据是行缓冲的,你会立即看到数据 . 如果一个管道,stdout数据是块缓冲的,你只看到数据堆积很多或程序刷新管道 .
如果要获取程序输出,则必须使用管道,程序以缓冲模式运行 . 在linux上,你可以通过创建一个假的控制台(伪tty,pty,...)来欺骗程序 . pty模块,pexpect和其他人这样做 .
在Windows上,我不知道有什么方法可以让它工作 . 如果您控制正在运行的程序,请经常刷新它 . 否则,在Windows徽标上徒劳地眩光 . 如果您希望提前结束,您甚至可以在下次相亲时提及问题 . 但我想不出更多 .
(如果有人知道修复,我想听听 . 我已经看到一些试图打开Windows控制台和屏幕的代码,但这些解决方案不断丢失数据 . 如果有环回字符,它应该可以工作那里的设备) .
问题是被写入的子进程在写入stdout后没有刷新 . 感谢J.F.和Tdelaney指出我正确的方向 . 我在这里向开发者提出了这个问题:http://www.imagemagick.org/discourse-server/viewtopic.php?f=2&t=26276&p=115545#p115545
除了更改子进程源之外,在Windows中似乎没有解决此问题的方法 . 也许如果你将子进程的输出重定向到可能有效的NamedTemporaryFile,但我还没有对它进行测试,我认为它将被锁定在Windows中,因此父进程和子进程中只有一个可以立即打开它 . 不是不可克服但令人讨厌 . 可能还有一种方法可以通过stdbuf的unixutils端口执行应用程序,或类似于J.F.建议的那样:Python C program subprocess hangs at "for line in iter"
如果您可以访问正在调用的子进程的源代码,则可以始终在禁用缓冲的情况下重新编译它 . 在C中禁用stdout上的缓冲很简单:
或设置每行缓冲而不是块缓冲:
另见:Python C program subprocess hangs at "for line in iter"
希望这可以帮助其他人 .
你可以尝试在listener.py结束时关闭管道吗?我认为这是问题所在