如何从子流程中获取实时输出流?
How to get live stream of output from a subprocess?
我正在尝试从 运行 Python 子进程中提取输出。为简单起见,我创建了一个 C 可执行文件,它每秒打印 0、1、2 等并无限期运行。
我的 Python 脚本以及类似想法的其他一些变体似乎在 5 分钟内什么都不做,然后一次将 300 行的一大块打印到终端。相反,我试图让它每秒打印一行。使用 Python 3.5.
import subprocess
import os
import sys
from time import sleep
def start_program():
args = ['./test_program']
p = subprocess.Popen(args, stdout=subprocess.PIPE, universal_newlines=True, bufsize=1)
return p
def print_output(p):
for line in p.stdout:
print(line, end='')
def main():
p = start_program()
print_output(p)
main()
问题是您的 C 程序检测到输出不会发送到 TTY,因此正在缓冲它。我假设你的 C 程序是这样的:
#include <stdio.h>
#include <unistd.h>
int main(void) {
for(int i = 0; i < 300; ++i) {
printf("%d\n", i);
sleep(1);
}
}
有两种方法可以修复它:
- 编辑您的 C 程序以执行
fflush(stdout);
循环的每次迭代或 setvbuf
以在开始时禁用缓冲
- 编辑您的 Python 程序以将您的 C 程序包装在
stdbuf
中,如下所示:args = ['stdbuf', '-oL', './test_program']
基础问题已由 @Joseph Sible-Reinstate Monica 描述,但您也可能面临临时阻塞问题。使用 process.stdout.readline()
或 for line in process.stdout:
使脚本等待 process.stdout
.
中的新行
在读取数据之前分析数据的可用性,可以实时接收和处理数据,无需等待。
主文件:
import subprocess
from time import sleep
process = subprocess.Popen(('python', 'subTest.py'), stdout=subprocess.PIPE)
while True:
sleep(0.7) #do smth
bytes_number = process.stdout.seek(0, 2)
if bytes_number:
print('number of new bytes: ', bytes_number)
process.stdout.seek(0, 0)
print(process.stdout.read(bytes_number))
if process.poll() is not None and not bytes_number:
break
print('done!')
如果您 运行 另一个 python 脚本而不是 C-executable 您还需要使用 stdout.flush()
(模拟 Python 中的 fflush(stdout)
) .
子进程文件:
from sys import stdout
from time import sleep
for i in range(10):
sleep(0.2) #do smth
stdout.write(str(i) + '/')
stdout.flush()
我正在尝试从 运行 Python 子进程中提取输出。为简单起见,我创建了一个 C 可执行文件,它每秒打印 0、1、2 等并无限期运行。
我的 Python 脚本以及类似想法的其他一些变体似乎在 5 分钟内什么都不做,然后一次将 300 行的一大块打印到终端。相反,我试图让它每秒打印一行。使用 Python 3.5.
import subprocess
import os
import sys
from time import sleep
def start_program():
args = ['./test_program']
p = subprocess.Popen(args, stdout=subprocess.PIPE, universal_newlines=True, bufsize=1)
return p
def print_output(p):
for line in p.stdout:
print(line, end='')
def main():
p = start_program()
print_output(p)
main()
问题是您的 C 程序检测到输出不会发送到 TTY,因此正在缓冲它。我假设你的 C 程序是这样的:
#include <stdio.h>
#include <unistd.h>
int main(void) {
for(int i = 0; i < 300; ++i) {
printf("%d\n", i);
sleep(1);
}
}
有两种方法可以修复它:
- 编辑您的 C 程序以执行
fflush(stdout);
循环的每次迭代或setvbuf
以在开始时禁用缓冲 - 编辑您的 Python 程序以将您的 C 程序包装在
stdbuf
中,如下所示:args = ['stdbuf', '-oL', './test_program']
基础问题已由 @Joseph Sible-Reinstate Monica 描述,但您也可能面临临时阻塞问题。使用 process.stdout.readline()
或 for line in process.stdout:
使脚本等待 process.stdout
.
在读取数据之前分析数据的可用性,可以实时接收和处理数据,无需等待。
主文件:
import subprocess
from time import sleep
process = subprocess.Popen(('python', 'subTest.py'), stdout=subprocess.PIPE)
while True:
sleep(0.7) #do smth
bytes_number = process.stdout.seek(0, 2)
if bytes_number:
print('number of new bytes: ', bytes_number)
process.stdout.seek(0, 0)
print(process.stdout.read(bytes_number))
if process.poll() is not None and not bytes_number:
break
print('done!')
如果您 运行 另一个 python 脚本而不是 C-executable 您还需要使用 stdout.flush()
(模拟 Python 中的 fflush(stdout)
) .
子进程文件:
from sys import stdout
from time import sleep
for i in range(10):
sleep(0.2) #do smth
stdout.write(str(i) + '/')
stdout.flush()