我正在通过Python执行外部程序。我想知道使用subprocess.Popen()
或subprocess.call()
来调用外部程序的最佳选择是什么。此外,我需要测量外部程序使用的经过时间,内存量和CPU。我听说过psutil
,但我真的不知道该选择哪个。
答案 0 :(得分:7)
我还需要测量extern程序使用的经过时间,内存量和cpu
(我假设您只需要平台rusage
中提供的信息。而且,由于Windows根本没有这样的东西,我也会假设您不关心Windows如果您需要其他信息,这些信息仅以特定于平台的方式提供(读取Linux的proc
文件系统,或者调用AIX的监视器API,或者其他),那么使用stdlib几乎无法做到这一点,并且psutil
答案是唯一的答案。)
subprocess
库包含调用fork
,然后调用子级中的execv
- 家庭功能以及父级中的waitpid
- 家庭功能。 (你可以从源call
开始,然后从那里追溯到其他调用来看到这一点。)
不幸的是,从孩子那里获取资源使用的简便方法是拨打wait3
或wait4
,而不是wait
或waitpid
。所以subprocess
让你疯狂地接近你想要的东西,但不是那么。
但你有几个选择:
getrusage(RUSAGE_CHILDREN)
。psutil
(或特定于平台的代码)从proc.pid
获取资源信息。psutil
执行所有操作,只留下subprocess
。subprocess.Popen
子类化为覆盖其wait
方法。最后一个比听起来简单得多。如果您查看源代码,实际上只有3个地方os.waitpid
被调用,其中只有一个会影响您的代码;我认为这是_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
现在:
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上使用它,依此类推......