python 子进程:使用 subprocess.PIPE 时输出顺序发生变化
python subprocess: order of output changes when using subprocess.PIPE
当我编写一个名为 outer.py
的 python 脚本时,其中包含
p = subprocess.Popen(['./inner.py'])
print('Called inner.py without options, waiting for process...')
p.wait()
print('Waited for inner.py without options')
p = subprocess.Popen(['./inner.py'], stdout=subprocess.PIPE)
print('Called inner.py with PIPE, communicating...')
b_out, b_err = p.communicate()
out = b_out.decode('utf8')
print('out is "{}"'.format(out))
还有一个 inner.py
包含
print("inner: Echoing Hallo")
p = subprocess.Popen(['echo', 'hallo'])
print("inner: Waiting for Echo to finish...")
p.wait()
print("inner: Waited for Echo")
我从终端调用 outer.py
时得到以下信息:
Called inner.py without options, waiting for process...
inner: Echoing Hallo
inner: Waiting for Echo to finish...
hallo
inner: Waited for Echo
Waited for inner.py without options
Called inner.py with PIPE, communicating...
out is "hallo
inner: Echoing Hallo
inner: Waiting for Echo to finish...
inner: Waited for Echo
"
为什么在使用 stdout=subprocess.PIPE
调用 inner.py
时,在捕获的输出中 "hallo" 出现在 "inner: Echoing Hallo" 之前?
我猜想,出于某种原因(与管道和 ttys 相关,请参阅 this comment),inner.py
Python 进程的输出在您第一次使用时是无缓冲的调用它,并在你第二次调用它时进行缓冲。第一次使用无缓冲输出时,您会按照预期的顺序将结果写入您的 tty。第二次,通过缓冲,首先刷新 echo
命令的输出(因为 echo
运行并终止),然后立即显示 inner.py
进程的所有输出, 当 python
终止时。如果您禁用 inner.py
的输出缓冲,您应该在两种情况下获得相同的输出。
通过设置 PYTHONUNBUFFERED
环境变量,或使用 -u
开关调用 python,或在每个 [=19] 之后显式调用 sys.stdout.flush()
来禁用输出缓冲=](或 Python 3 上的 print(..., flush=True)
)。
管道和 ttys 行为之间的区别似乎是 general behaviour of stdio
:输出到 ttys 是行缓冲的(因此,在您的代码中,逐行读取,它似乎是无缓冲的), 而管道的输出是缓冲的。
当我编写一个名为 outer.py
的 python 脚本时,其中包含
p = subprocess.Popen(['./inner.py'])
print('Called inner.py without options, waiting for process...')
p.wait()
print('Waited for inner.py without options')
p = subprocess.Popen(['./inner.py'], stdout=subprocess.PIPE)
print('Called inner.py with PIPE, communicating...')
b_out, b_err = p.communicate()
out = b_out.decode('utf8')
print('out is "{}"'.format(out))
还有一个 inner.py
包含
print("inner: Echoing Hallo")
p = subprocess.Popen(['echo', 'hallo'])
print("inner: Waiting for Echo to finish...")
p.wait()
print("inner: Waited for Echo")
我从终端调用 outer.py
时得到以下信息:
Called inner.py without options, waiting for process...
inner: Echoing Hallo
inner: Waiting for Echo to finish...
hallo
inner: Waited for Echo
Waited for inner.py without options
Called inner.py with PIPE, communicating...
out is "hallo
inner: Echoing Hallo
inner: Waiting for Echo to finish...
inner: Waited for Echo
"
为什么在使用 stdout=subprocess.PIPE
调用 inner.py
时,在捕获的输出中 "hallo" 出现在 "inner: Echoing Hallo" 之前?
我猜想,出于某种原因(与管道和 ttys 相关,请参阅 this comment),inner.py
Python 进程的输出在您第一次使用时是无缓冲的调用它,并在你第二次调用它时进行缓冲。第一次使用无缓冲输出时,您会按照预期的顺序将结果写入您的 tty。第二次,通过缓冲,首先刷新 echo
命令的输出(因为 echo
运行并终止),然后立即显示 inner.py
进程的所有输出, 当 python
终止时。如果您禁用 inner.py
的输出缓冲,您应该在两种情况下获得相同的输出。
通过设置 PYTHONUNBUFFERED
环境变量,或使用 -u
开关调用 python,或在每个 [=19] 之后显式调用 sys.stdout.flush()
来禁用输出缓冲=](或 Python 3 上的 print(..., flush=True)
)。
管道和 ttys 行为之间的区别似乎是 general behaviour of stdio
:输出到 ttys 是行缓冲的(因此,在您的代码中,逐行读取,它似乎是无缓冲的), 而管道的输出是缓冲的。