【发布时间】:2014-07-10 21:28:00
【问题描述】:
我有一个 Python 脚本 (popen.py),它运行另一个 Python 脚本 (counter.py) 作为子进程,输出重定向到 /tmp/counter.log。我使用的代码是:
/tmp/counter.py
#!/usr/bin/env python2
import time
i = 0
while True:
print i
i +=1
time.sleep(1)
/tmp/popen.py
#!/usr/bin/env python2
import subprocess
f = open("/tmp/counter.log", "a+")
p = subprocess.Popen("/tmp/counter.py", stdout=f, stderr=f, bufsize=1)
但是,当我运行 popen.py 时,子进程被创建并保持运行,但是在输出达到 4096 字节之前,没有任何内容被写入 /tmp/counter.log,然后它似乎被刷新到文件中。
有什么方法可以让我的子进程在不修改 counter.py 脚本本身的情况下逐行写入日志文件?
我不想修改counter.py 的原因是子进程可能并不总是在运行 Python 脚本。我已经尝试过运行一个小型可执行文件(用 C 编写)并发生同样的问题。
我已经尝试为该文件编写一个自刷新包装器并将其用于stdout,如here 所述,但这也不起作用。
我已经对lsof 和strace 进行了一些调试,这就是我设法找到的结果:
lsof(文件描述符)
手动运行 /tmp/counter.py
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
python2 629 daniel 0u CHR 136,0 0t0 3 /dev/pts/0
python2 629 daniel 1u CHR 136,0 0t0 3 /dev/pts/0
python2 629 daniel 2u CHR 136,0 0t0 3 /dev/pts/0
通过 /tmp/popen.py 运行 /tmp/counter.py
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
python2 638 daniel 0u CHR 136,0 0t0 3 /dev/pts/0
python2 638 daniel 1u REG 202,0 0 768 /tmp/counter.log
python2 638 daniel 2u REG 202,0 0 768 /tmp/counter.log
strace(while 循环中的系统调用)
手动运行 /tmp/counter.py
select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
write(1, "11\n", 3) = 3
select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
write(1, "12\n", 3) = 3
select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
write(1, "13\n", 3) = 3
select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
write(1, "14\n", 3) = 3
select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
write(1, "15\n", 3) = 3
通过 /tmp/popen.py 运行 /tmp/counter.py
select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
...
write(1, "11\n12\n13\n14\n15\n16\n17\n18\n"..., 4096) = 4096
【问题讨论】:
-
您似乎没有使用您的
Popen实例的communicate方法。还有,在counter.py,直接写sys.stdout然后flush怎么样? -
@LukasGraf 这确实有效。无论如何我可以纯粹在代码中实现这一点吗?我不想在
Popen的调用行中手动指定它或通过编辑counter.py。 -
@Midnighter 我不需要使用
communicate因为我不想与子进程通信,在我的问题中我明确提到我希望能够做到这一点更改counter.py。 -
@DanielGibbs 您不能在另一个进程中更改文件的缓冲区设置。在不更改
counter.py的情况下,您可以使用 Python 解释器和-u(无缓冲)选项启动该脚本。编辑:在启动counter.py之前交替设置PYTHONUNBUFFERED环境变量。 -
Popen()constructor 的文档说将bufsize设置为 0 表示无缓冲,我认为这就是您想要的。
标签: python stdout stderr child-process