测量外部程序使用的时间、内存量和 CPU

2024-01-02

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


我还需要测量外部程序使用的时间、内存量和CPU

(我假设您只需要平台中可用的信息rusage http://linux.die.net/man/2/getrusage。而且,由于 Windows 根本没有这样的东西,我也假设您不关心 Windows。如果您需要只能以某种特定于平台的方式获得的附加信息(读取 Linux 的proc文件系统,或者调用 AIX 的监视器 API,或者其他什么),你几乎无法使用 stdlib 来做到这一点,并且psutil答案是唯一的。)

The subprocess库结束调用fork https://docs.python.org/3/library/os.html#os.fork,然后一个execv https://docs.python.org/3/library/os.html#os.execv- 孩子的家庭功能和waitpid https://docs.python.org/3/library/os.html#os.waitpid- 父母的家庭功能。 (您可以从源代码开始看到这一点call https://hg.python.org/cpython/file/3/Lib/subprocess.py#l529并从那里追踪其他呼叫。)

不幸的是,从孩子那里获取资源使用情况的简单方法是调用wait3 or wait4 https://docs.python.org/3/library/os.html#os.wait4, not wait or waitpid. So subprocess让你疯狂地接近你想要的东西,但还没有完全实现。

但你有几个选择:

  • 如果你只有一个子进程,getrusage(RUSAGE_CHILDREN) https://docs.python.org/3/library/resource.html#resource.getrusage是你所需要的全部。
  • 您可以启动该进程,然后使用psutil(或特定于平台的代码)从中获取资源信息proc.pid在收割孩子之前。
  • 您可以使用psutil做完一切,离开subprocess behind.
  • 你可以子类化subprocess.Popen覆盖它的wait method.

最后一个比听起来简单得多。如果你看一下源码,只有3个地方os.waitpid实际上被调用,并且只有其中一个会影响您的代码;我认为这是其中的一个_try_wait https://hg.python.org/cpython/file/default/Lib/subprocess.py#l1510。所以(未经测试):

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

And now:

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

与使用混合动力进行比较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))

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

测量外部程序使用的时间、内存量和 CPU 的相关文章

随机推荐