【问题标题】:Accessing stdout when using "time" in python subproces在 python 子进程中使用“时间”时访问标准输出
【发布时间】:2014-12-12 07:20:41
【问题描述】:

我一直在使用time 命令在我的shell 中进行一些手动基准测试。我想通过编写一个 python 脚本来扩展我的基准测试,该脚本既可以自动化测试,又可以让我访问时间数据,以便我可以以我选择的格式(可能是 csv)记录它。我看到有 timeit 模块,但这似乎更适用于对 python 代码进行基准测试,我在这里尝试对在命令行中运行的程序进行基准测试。

这是我一直在手动做的:

time program -aflag -anotherflag

我最初尝试在脚本中实现这一点如下:

cmnd = ['time', 'program', 'aflag', 'anotherflag']
p = subprocess.Popen(cmnd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate
print out
print err

我可以很好地访问time 的输出——它被传送到stderr,但是我没有在stdout 中得到program 的输出。如果我从cmnd 中删除time 并将shell=False 更改为True,然后我会在stdout 中获得程序的输出——但显然不是time 的输出,这就是重点。

cmnd = ['program', 'aflag', 'anotherflag']
p = subprocess.Popen(cmnd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate
print out
print err

如果我用shell=Truetime 添加回cmdnd,我会得到时间的输出,但program 实际上并没有运行。

我怎样才能让两者都工作?

【问题讨论】:

  • 请复制粘贴一个 actualll 简短的独立程序来演示您的错误。请不要只是输入它,而是测试它,运行它,然后复制粘贴它。谢谢。见stackoverflow.com/help/mcve
  • shell 中的time 命令不显示结果!!它只是显示时间real,os,user
  • 修复测试程序中的语法错误并将cmnd 替换为cmnd = ['time', 'ls', '-s', '-h'] 后,我在outerr 中都得到了正确的结果。 This link 包含我的程序。
  • 那么你的程序是什么?它是python代码吗?还是...?
  • @Kasra:比这更糟糕; /usr/bin/time 程序和不同 shell 中名为 time 的 shell 内建函数在处理程序的输出和/或错误方面都不同,这使得新手在围绕命令编写代码时非常困惑……

标签: python shell time stdout benchmarking


【解决方案1】:

与其尝试让它工作,为什么不使用resource 模块中 Python 内置的功能?

import resource
import subprocess

cmd = ['program', 'aflag', 'anotherflag']
p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
usage = resource.getrusage(resource.RUSAGE_CHILDREN)
print out
print err
print usage.ru_utime, usage.ru_stime, usage.ru_utime+usage.ru_stime

如果您需要区分同时运行的不同子进程,getrusage 显然是不够的。在这种情况下,您需要使用wait4 或类似方法来获取每个进程的资源使用情况。这使您对Popen 的使用更加复杂。对于这种情况,您可能想要做的是子类化或 fork subprocess 代码(但如果您使用的是 3.1 或更早版本,请确保使用 subprocess32 反向端口以避免 communicate 中的错误,这样该类实际上具有您要挂钩的方法...)并将the _try_wait method更改为使用wait4而不是waitpid并将额外的结果存储在例如self.rusage中,以便您以后可以访问它。

我认为这样的事情会起作用:

import subprocess32

class Popen(subprocess32.Popen):
    def _try_wait(self, wait_flags):
        """All callers to this function MUST hold self._waitpid_lock."""
        try:
            (pid, sts, rusage) = _eintr_retry_call(os.wait4, self.pid, wait_flags)
            if pid == self.pid:
                self.rusage = rusage
        except OSError as e:
            if e.errno != errno.ECHILD:
                raise
            pid = self.pid
            sts = 0
        return (pid, sts)

cmd = ['program', 'aflag', 'anotherflag']
p = Popen(cmd, shell=False, stdout=subprocess32.PIPE, stderr=subprocess32.PIPE)
out, err = p.communicate()
print out
print err
try:
    usage = p.rusage
except AttributeError:
    print 'Child died before we could wait on it, no way to get rusage'        
else:
    print usage.ru_utime, usage.ru_stime, usage.ru_utime+usage.ru_stime

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-09
    • 2016-12-01
    • 2011-08-29
    • 2016-03-26
    • 1970-01-01
    • 2016-02-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多