Как вы можете профилировать скрипт Python? - PullRequest
1123 голосов
/ 24 февраля 2009

Project Euler и другие конкурсы по кодированию часто имеют максимальное время для запуска или люди хвастаются тем, насколько быстро работает их конкретное решение. В случае с Python подходы иногда оказываются несколько хитрыми, то есть добавление временного кода к __main__.

Как правильно определить, сколько времени занимает запуск программы на Python?

Ответы [ 23 ]

29 голосов
/ 02 марта 2015

pprofile

line_profiler (уже представлен здесь) также вдохновил pprofile, который описывается как:

Линейная гранулярность, детерминистический и статистический чистый Python Profiler

Он обеспечивает гранулярность строки как line_profiler, является чистым Python, может использоваться как отдельная команда или модуль и может даже генерировать файлы в формате callgrind, которые можно легко анализировать с помощью [k|q]cachegrind.

vprof

Существует также vprof , пакет Python, описываемый как:

[...] предоставление богатых и интерактивных визуализаций для различных характеристик программы Python, таких как время работы и использование памяти.

heatmap

15 голосов
/ 04 августа 2018

Я недавно создал тунец для визуализации Python runtime и профилей импорта; это может быть полезно здесь.

enter image description here

Установить с

pip3 install tuna

Создать профиль времени выполнения

python -mcProfile -o program.prof yourfile.py

или профиль импорта (требуется Python 3.7+)

python -X importprofile yourfile.py 2> import.log

Тогда просто запустите тунец на файле

tuna program.prof
12 голосов
/ 21 августа 2015

Есть много хороших ответов, но они либо используют командную строку, либо какую-то внешнюю программу для профилирования и / или сортировки результатов.

Я действительно упустил какой-то способ, которым я мог бы использовать в своей IDE (eclipse-PyDev), не касаясь командной строки и ничего не устанавливая. Итак, вот оно.

Профилирование без командной строки

def count():
    from math import sqrt
    for x in range(10**5):
        sqrt(x)

if __name__ == '__main__':
    import cProfile, pstats
    cProfile.run("count()", "{}.profile".format(__file__))
    s = pstats.Stats("{}.profile".format(__file__))
    s.strip_dirs()
    s.sort_stats("time").print_stats(10)

См. документы или другие ответы для получения дополнительной информации.

12 голосов
/ 09 ноября 2011

После ответа Джо Шоу о том, что многопоточный код не работает должным образом, я понял, что метод runcall в cProfile просто выполняет self.enable() и self.disable() вызовы вокруг вызова профилированной функции, так что вы можете просто сделать что вы сами и имеете любой код, который вы хотите промежуточный с минимальным вмешательством в существующий код.

10 голосов
/ 24 февраля 2009

В исходном коде Virtaal есть очень полезный класс и декоратор, которые могут упростить профилирование (даже для определенных методов / функций). Выходные данные можно очень удобно просматривать в KCacheGrind.

9 голосов
/ 30 марта 2015

cProfile отлично подходит для быстрого профилирования, но большую часть времени он заканчивался для меня ошибками. Функция runctx решает эту проблему, правильно инициализируя окружение и переменные, надеясь, что это может кому-то пригодиться:

import cProfile
cProfile.runctx('foo()', None, locals())
6 голосов
/ 19 февраля 2014

Мой способ заключается в использовании yappi (https://code.google.com/p/yappi/).. Это особенно полезно в сочетании с RPC-сервером, на котором (даже только для отладки) вы регистрируете метод для запуска, остановки и печати данных профилирования, например, таким образом:

@staticmethod
def startProfiler():
    yappi.start()

@staticmethod
def stopProfiler():
    yappi.stop()

@staticmethod
def printProfiler():
    stats = yappi.get_stats(yappi.SORTTYPE_TTOT, yappi.SORTORDER_DESC, 20)
    statPrint = '\n'
    namesArr = [len(str(stat[0])) for stat in stats.func_stats]
    log.debug("namesArr %s", str(namesArr))
    maxNameLen = max(namesArr)
    log.debug("maxNameLen: %s", maxNameLen)

    for stat in stats.func_stats:
        nameAppendSpaces = [' ' for i in range(maxNameLen - len(stat[0]))]
        log.debug('nameAppendSpaces: %s', nameAppendSpaces)
        blankSpace = ''
        for space in nameAppendSpaces:
            blankSpace += space

        log.debug("adding spaces: %s", len(nameAppendSpaces))
        statPrint = statPrint + str(stat[0]) + blankSpace + " " + str(stat[1]).ljust(8) + "\t" + str(
            round(stat[2], 2)).ljust(8 - len(str(stat[2]))) + "\t" + str(round(stat[3], 2)) + "\n"

    log.log(1000, "\nname" + ''.ljust(maxNameLen - 4) + " ncall \tttot \ttsub")
    log.log(1000, statPrint)

Затем, когда ваша программа заработает, вы можете в любое время запустить профилировщик, вызвав метод startProfiler RPC и выгрузив информацию о профилировании в файл журнала, вызвав printProfiler (или измените метод rpc, чтобы он возвращался вызывающей стороне) и получить такой вывод:

2014-02-19 16:32:24,128-|SVR-MAIN  |-(Thread-3   )-Level 1000: 
name                                                                                                                                      ncall     ttot    tsub
2014-02-19 16:32:24,128-|SVR-MAIN  |-(Thread-3   )-Level 1000: 
C:\Python27\lib\sched.py.run:80                                                                                                           22        0.11    0.05
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\xmlRpc.py.iterFnc:293                                                22        0.11    0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\serverMain.py.makeIteration:515                                                    22        0.11    0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\PicklingXMLRPC.py._dispatch:66                                       1         0.0     0.0
C:\Python27\lib\BaseHTTPServer.py.date_time_string:464                                                                                    1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\_psmswindows.py._get_raw_meminfo:243     4         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.decode_request_content:537                                                                          1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\_psmswindows.py.get_system_cpu_times:148 4         0.0     0.0
<string>.__new__:8                                                                                                                        220       0.0     0.0
C:\Python27\lib\socket.py.close:276                                                                                                       4         0.0     0.0
C:\Python27\lib\threading.py.__init__:558                                                                                                 1         0.0     0.0
<string>.__new__:8                                                                                                                        4         0.0     0.0
C:\Python27\lib\threading.py.notify:372                                                                                                   1         0.0     0.0
C:\Python27\lib\rfc822.py.getheader:285                                                                                                   4         0.0     0.0
C:\Python27\lib\BaseHTTPServer.py.handle_one_request:301                                                                                  1         0.0     0.0
C:\Python27\lib\xmlrpclib.py.end:816                                                                                                      3         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.do_POST:467                                                                                         1         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.is_rpc_path_valid:460                                                                               1         0.0     0.0
C:\Python27\lib\SocketServer.py.close_request:475                                                                                         1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\__init__.py.cpu_times:1066               4         0.0     0.0 

Это может быть не очень полезно для коротких сценариев, но помогает оптимизировать процессы серверного типа, особенно с учетом того, что метод printProfiler можно вызывать несколько раз с течением времени для профилирования и сравнения, например. различные сценарии использования программы.

3 голосов
/ 13 октября 2012

Вы когда-нибудь хотели знать, что, черт возьми, делает этот скрипт на Python? Введите Осмотрите Shell. Inspect Shell позволяет печатать / изменять глобальные переменные и запускать функционирует без прерывания работающего скрипта. Теперь с автозаполнение и история команд (только в linux).

Проверьте, что Shell не является отладчиком в стиле pdb.

https://github.com/amoffat/Inspect-Shell

Вы можете использовать это (и ваши наручные часы).

3 голосов
/ 29 апреля 2015

Новый инструмент для обработки профилирования в Python - это PyVmMonitor: http://www.pyvmmonitor.com/

Имеет некоторые уникальные функции, такие как

  • Присоединение профилировщика к запущенной (CPython) программе
  • Профилирование по требованию с интеграцией Yappi
  • Профиль на другой машине
  • Поддержка нескольких процессов (многопроцессорность, django ...)
  • Живая выборка / просмотр ЦП (с выбором диапазона времени)
  • Детерминированное профилирование через интеграцию cProfile / профиля
  • Анализ существующих результатов PStats
  • Открытые файлы DOT
  • Программный доступ к API
  • Группировка образцов по методу или линии
  • интеграция PyDev
  • интеграция PyCharm

Примечание: он коммерческий, но бесплатный для открытого исходного кода.

3 голосов
/ 21 марта 2015

Добавить к https://stackoverflow.com/a/582337/1070617,

Я написал этот модуль, который позволяет вам использовать cProfile и легко просматривать его результаты. Больше здесь: https://github.com/ymichael/cprofilev

$ python -m cprofilev /your/python/program
# Go to http://localhost:4000 to view collected statistics.

Также см .: http://ymichael.com/2014/03/08/profiling-python-with-cprofile.html о том, как понять собранную статистику.

...