test.py
import time
for x in range(0, 10, 1):
print(x)
time.sleep(1)
字符串python test.py
打印真实的时间,即每秒一个数字
0
1
2
3
4
5
6
7
8
9
型
现在,我想通过下面的子进程在另一个名为run.py
的脚本中运行test.py
run.py
import subprocess
from subprocess import PIPE, STDOUT
proc = subprocess.Popen(
'python test.py',
stdout=PIPE,
stderr=STDOUT,
shell=True,
encoding="utf-8",
errors="replace",
universal_newlines=True,
text=True,
bufsize=1,
)
while (realtime_output := proc.stdout.readline()) != "" or proc.poll() is None:
print(realtime_output.strip(), flush=True)
型
当我运行python run.py
时,输出不是真实的时间(没有每秒打印的数字)
奇怪的是,如果我将test.py
中的代码修改为print(x, flush=True)
,那么python run.py
每秒打印一次。
有没有办法在run.py
中通过subprocess
输出真实的时间而不修改test.py
的打印语句?
1条答案
按热度按时间zengzsys1#
bufsize=1
正在更改父进程proc.stdout
文件句柄中的 input 缓冲区。它不会以任何方式影响子进程的 output 缓冲区。当Python的stdout
连接到管道而不是终端时,它会自动进入块缓冲模式。将
test.py
更改为使用print(x, flush=True)
,它将刷新每个print
上的输出缓冲区,无论是连接到终端、文件还是管道,您在父进程中禁用缓冲区的工作将按预期生效。或者,将子进程的run改为将
-u
传递给python
,使其不受缓冲,例如'python -u test.py'
。这将完全禁用输出缓冲,消除对flush=True
的需要(但它会使程序只需要flush=True
* 有时 *,但写出来很多没有它,运行得更慢)。作为旁注:几乎没有理由使用
shell=True
(您可以/应该使用它的唯一时间是如果命令行的任何组件都不来自不受信任的数据源,例如用户,并且您需要使用shell内置和/或shell元字符,并且您确信您没有意外地使用任何这样的元字符)。您的子进程将避免不必要的 shell Package 层(这可能会引入额外的缓冲复杂性),通过将'python test.py'
更改为['python', 'test.py']
(['python', '-u', 'test.py']
用于无缓冲输出),并删除shell=True,
,一切都应该更有效,更安全地运行。你也可以去掉
universal_newlines=True,
,因为text=True
的意思是完全一样的;如果你只支持允许text=True
的Python版本,那么universal_newlines=True
对你来说毫无用处。