Я выполняю внешнюю программу через Python. Я хочу знать, что является лучшим выбором для вызова внешней программы, с помощью subprocess.Popen()
или с помощью subprocess.call()
. Кроме того, мне нужно измерить прошедшее время, объем памяти и ЦП, используемые внешней программой. Я слышал о psutil
, но не знаю, что выбрать.
измерять прошедшее время, объем памяти и процессор, используемый внешней программой
Ответы (1)
также мне нужно измерить прошедшее время, объем памяти и процессор, используемый внешней программой
(Я предполагаю, что вам нужна только информация, доступная в rusage
вашей платформы. И , так как в Windows такого вообще нет, я также предполагаю, что Windows вам безразлична. API-интерфейсы мониторинга или что-то еще), вы практически не можете сделать это с помощью stdlib, и ответ psutil
является единственным.)
Библиотека subprocess
завершает вызов fork
, затем execv
-family в дочернем элементе и waitpid
— семейная функция в родительском элементе. (Вы можете убедиться в этом, начав с исходного кода до call
и отслеживание других звонков оттуда.)
К сожалению, простой способ узнать об использовании ресурсов от дочернего элемента — это вызвать wait3
или wait4
, а не wait
или waitpid
. Так что 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
И сейчас:
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 и так далее…
psutil
нельзя использовать после того, как вы пожинаете плоды процесса, некоторые — можно, и список зависит от платформы. Именно поэтому гибридное решение (используйте subprocess
для запуска вещей, используйте psutil
для их измерения) является худшим из вариантов… Если вам не нужно работать с psutil 1.x и psutil.Popen
имеет достаточную функциональность, попробуйте. Я считаю, что он дает вам подкласс psutil.Process
и что вы гарантированно сможете получить доступ к его материалам между вызовами communicate
и wait
, но я могу ошибаться.
- person abarnert; 21.10.2014
wait
. Как я объяснил в своем предыдущем комментарии, я думаю, что класс psutil.Process
(в версии 2.0+) позволяет вам вызывать communicate
, а затем wait
, но класс subprocess.Process
определенно этого не делает (потому что communicate
имеет неявный wait
в нем). Если я неправильно помню, возможно, есть другой вариант.
- person abarnert; 21.10.2014
subprocess.call
— это тонкая оболочка вокругsubprocess.Popen
. Взглянув на источник, вы должны понять различия. - person mgilson   schedule 21.10.2014