测量extern程序使用的经过时间,内存量和CPU

C. *_*rto 1 python shell subprocess psutil

我正在通过Python执行外部程序.我想知道什么是调用外部程序,最好的选择subprocess.Popen()还是有subprocess.call().此外,我需要测量外部程序使用的经过时间,内存量和CPU.我听说过psutil,但我真的不知道该选哪个.

aba*_*ert 7

我还需要测量extern程序使用的经过时间,内存量和CPU

(我假设您只需要平台上提供的信息rusage.而且,由于Windows根本没有这样的东西,我也会假设你不关心Windows.如果你需要额外的信息,那就是以某种特定于平台的方式提供(读取Linux的proc文件系统,或者调用AIX的监视器API,或其他任何方式),你几乎不能用stdlib做到这一点,psutil答案是唯一的.)

subprocess库包含调用fork,然后是execv子系统中的waitpid家庭功能和父系统中的家庭功能.(您可以通过从源开始call并从那里跟踪到其他调用来查看此内容.)

不幸的是,简单的方法来从一个孩子获得资源使用是打电话wait3或者wait4,不waitwaitpid.因此,subprocess让你疯狂地接近你想要的东西,但不是那么.

但是你有几个选择:

  • 如果您只有一个子进程,那getrusage(RUSAGE_CHILDREN)就是您所需要的.
  • 您可以启动该过程,然后使用psutil(或特定于平台的代码)从proc.pid收割孩子之前获取资源信息.
  • 你可以psutil用来做任何事情,留下subprocess来.
  • 您可以子类subprocess.Popen来覆盖其wait方法.

最后一个比听起来简单得多.如果查看源代码,os.waitpid实际调用的地方只有3个,其中只有一个会影响代码; 我认为这是其中之一_try_wait.所以(未经测试):

class ResourcePopen(subprocess.Popen):
    def _try_wait(self, wait_flags):
        """All callers to this function MUST hold self._waitpid_lock."""
        try:
            (pid, sts, res) = _eintr_retry_call(os.wait4, self.pid, wait_flags)
        except OSError as e:
            if e.errno != errno.ECHILD:
                raise
            # This happens if SIGCLD is set to be ignored or waiting
            # for child processes has otherwise been disabled for our
            # process.  This child is dead, we can't get the status.
            pid = self.pid
            sts = 0
        else:
            self.rusage = res
        return (pid, sts)

def resource_call(*popenargs, timeout=None, **kwargs):
    """Run command with arguments.  Wait for command to complete or
    timeout, then return the returncode attribute and resource usage.

    The arguments are the same as for the Popen constructor.  Example:

    retcode, rusage = call(["ls", "-l"])
    """
    with ResourcePopen(*popenargs, **kwargs) as p:
        try:
            retcode = p.wait(timeout=timeout)
            return retcode, p.rusage
        except:
            p.kill()
            p.wait()
            raise
Run Code Online (Sandbox Code Playgroud)

现在:

retcode, rusage = resource_call(['spam', 'eggs'])
print('spam used {}s of system time'.format(rusage.ru_stime))
Run Code Online (Sandbox Code Playgroud)

相比之下,使用混合psutil(在许多平台上以这种方式使用时甚至都无法工作......):

p = subprocess.Popen(['spam', 'eggs'])
ps = psutil.Process(p.pid)
p.wait()
print('spam used {}s of system time'.format(ps.cpu_times().system))
Run Code Online (Sandbox Code Playgroud)

当然后者并不是因为没有充分理由而变得更加复杂,它更复杂,因为它更加强大和灵活; 您还可以获得rusage不包含的各种数据,并且您可以在进程运行时每秒获取信息,而不是等到它完成,并且您可以在Windows上使用它,依此类推......