如何在输出很大的情况下管理Python中的子进程?

时间:2010-08-03 13:23:50

标签: python subprocess

我使用bash脚本控制长时间运行的模拟(小时,天,甚至几周),该脚本遍历所有需要的参数。如果只有一个模拟同时运行,则输出通过管道传输到“tee”,否则输出显然是“>”到输出文件。所有输出都是巨大的:一些日志文件大约2GB,甚至可能更大。

脚本正在运行,但是要维护。当我们添加一个新参数时,需要一些时间来调整脚本和其中的所有sed-foo。所以我把它移植到Python。它的工作很棒。

我现在唯一阻止我在生产中使用它的问题是我找不到调用Popen()来启动程序的正确方法。如果我通过将所有内容传递给文件而不显示任何输出来“静默”运行它,那么在模拟完成之前,python需要几千兆字节的ram。

这是代码snipet:

fh = open(logfile, "w")
pid = subprocess.Popen(shlex.split(command), stdout=fh)
pids.append(pid)

我已经阅读了很多有关Popen输出的内容,但是我知道将它连接到文件会在需要时刷新缓冲区吗?

也许子进程'Popen()不是最好的吗?什么是在不占用所有内存的情况下显示和保存程序输出到屏幕和文件的最佳方法?

感谢名单!

4 个答案:

答案 0 :(得分:2)

为什么不静默写入文件,然后tail呢?

您可以使用file.flush()清除Python的文件缓冲区。


Python将很乐意处理当前打开的文件中的新行。例如:

f = open( "spam.txt", "r" )
f.read()
# 'I like ham!'
# Now open up spam.txt in some other program and add a new line.
f.read()
# 'I like eggs too!'

答案 1 :(得分:0)

最简单的解决方案是更改代码,以便输出到stdout AND日志文件。然后,输出不会使用T形管或管道保存。

pipe_verbose = sys.stdout
pipe_silent  = open('/dev/null', 'w')

subprocess.Popen(shlex.split(command), stdout=pipe_silent)
subprocess.Popen(shlex.split(command), stdout=pipe_verbose)

最后我轮询()看看什么时候完成。

管道有很好的结果,如果我ctrl + c脚本,它也会杀死这个工作。如果我没有在Popen()中放入stdout = ...,那么作业将在后台继续。此外,python的CPU使用率保持在0%。管道上的readline循环会将其提高到100%......

答案 2 :(得分:0)

如果输出具有可靠出现的输出分隔符(表示输出部分结束的标记),则考虑执行“坏”操作并在单独的线程中从子进程读取stdout块并将各个块写入日志,每次写入时都闪烁它们。

在这里看一下从子进程'pipe:

的非阻塞读取的一些例子

How can I read all availably data from subprocess.Popen.stdout (non blocking)?

答案 3 :(得分:0)

不是分割模拟的输出,而是选择将其输入文件(或从模拟中写入文件,然后使用tail -f在控制台中查看最新输出。

示例模拟:

#!/bin/bash

while true; do
  echo $$ -- $(date +%s)
  sleep 1
done

或者也许:

#!/usr/bin/env python
import os, sys, time

while True:
  sys.stdout.write("%d -- %d\n"%(os.getpid(), time.time()) )
  sys.stdout.flush()
  time.sleep(1)

调用:

$ nohup ./simulation &> logfile &

观看输出:

$ tail -f logfile
1285 -- 1337166243
1285 -- 1337166244
1285 -- 1337166245
1285 -- 1337166246
1285 -- 1337166247
^C

备注:

  • 将stderr和stdout拆分为不同日志文件的加分点。
  • 不要将tee用于此类事情。它很脆弱,如果在管道端发生坏事,它会将错误传播给你的模拟。
  • 请注意我们如何记录模拟的PID,以便我们可以在启动后将其中止。建议您将其存储在pid文件而不是模拟日志中,纯粹是为了简化模拟杀死模拟。
  • 使用nohup。这将保护您的模拟运行,以防您关闭始发终端,或者如果X11崩溃(根据经验,这将在您的4天模拟完成98%并且您尚未实施检查点时发生......)。