В Project Euler и других конкурсах по кодированию часто указывается максимальное время выполнения, или люди хвастаются тем, как быстро выполняется их конкретное решение. В python иногда подходы несколько упрощены - например, добавление кода синхронизации в __main__
.
Какой хороший способ определить, как долго выполняется программа на python?
В состав Python входит профилировщик под названием cProfile. Он не только выдает общее время работы, но и проверяет каждую функцию отдельно и сообщает, сколько раз была вызвана каждая функция, что позволяет легко определить, где следует провести оптимизацию.
Вы можете вызвать его из кода или из интерпретатора, например, так:
import cProfile
cProfile.run('foo()')
Еще более полезно вызывать cProfile при запуске скрипта:
python -m cProfile myscript.py
Чтобы сделать это еще проще, я создал небольшой пакетный файл под названием 'profile.bat':
python -m cProfile %1
Так что все, что мне нужно сделать, это запустить:
profile euler048.py
И я получаю вот это:
1007 function calls in 0.061 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.061 0.061 <string>:1(<module>)
1000 0.051 0.000 0.051 0.000 euler048.py:2(<lambda>)
1 0.005 0.005 0.061 0.061 euler048.py:2(<module>)
1 0.000 0.000 0.061 0.061 {execfile}
1 0.002 0.002 0.053 0.053 {map}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler objects}
1 0.000 0.000 0.000 0.000 {range}
1 0.003 0.003 0.003 0.003 {sum}
EDIT: Обновлена ссылка на хороший видео ресурс с PyCon 2013 под названием. Python Profiling [Также через YouTube](
Некоторое время назад я сделал pycallgraph
, который создает визуализацию из вашего кода на Python. Редактировать: я'вэ обновлен пример для работы с 3.3, последняя версия на момент написания этой статьи.
После `Пип установить pycallgraph и установка [программ][ГВ] вы можете запустить его из командной строки:
pycallgraph graphviz -- ./mypythonscript.py
Или, вы можете профиль конкретной части кода:
from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput
with PyCallGraph(output=GraphvizOutput()):
code_to_profile()
Любой из этих будет генерировать pycallgraph.файл PNG
, похожее на картинку ниже:
Стоит отметить, что использование профилировщика работает (по умолчанию) только на основном потоке, и вы не получите никакой информации от других потоков, если вы их используете. Это может стать небольшой загвоздкой, так как об этом совершенно не упоминается в документации profiler documentation.
Если вы также хотите профилировать потоки, вам стоит обратить внимание на функцию threading.setprofile()
в документации.
Вы также можете создать свой собственный подкласс threading.Thread
для этого:
class ProfiledThread(threading.Thread):
# Overrides threading.Thread.run()
def run(self):
profiler = cProfile.Profile()
try:
return profiler.runcall(threading.Thread.run, self)
finally:
profiler.dump_stats('myprofile-%d.profile' % (self.ident,))
и использовать этот класс ProfiledThread
вместо стандартного. Это может дать вам больше гибкости, но я не уверен, что оно того стоит, особенно если вы используете сторонний код, который не будет использовать ваш класс.
Питон Вики-это отличная страница для профилирования ресурсов: http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Profiling_Code
как питон документы: http://docs.python.org/library/profile.html
как показали Крис Лоулор cProfile является отличным инструментом и может легко использоваться для печати на экран:
python -m cProfile -s time mine.py <args>
или в файл:
python -m cProfile -o output.file mine.py <args>
ПС> если вы используете Ubuntu, убедитесь в том, чтобы установить Python-профиль
sudo apt-get install python-profiler
При выводе в файл можно получить хорошие визуализации, используя следующие инструменты
PyCallGraph : инструмент для создания вызова графических изображений <БР> установка:<БР>
sudo pip install pycallgraph
выполнить:
pycallgraph mine.py args
вид:
gimp pycallgraph.png
Вы можете использовать все что угодно для просмотра файла png, я использовал gimp<БР> К сожалению, я часто получаю
точка: график слишком большим для Каира-рендер битмапов. Масштабирование по 0.257079, чтобы соответствовать
что делает мои снимки непригодно небольшой. Так я вообще создать SVG-файлы:
pycallgraph -f svg -o pycallgraph.svg mine.py <args>
ПС> убедитесь, что для установки программ (которые предоставляет программа Точка):
sudo pip install graphviz
Альтернативные графиков, используя gprof2dot через @макси / @quodlibetor :
sudo pip install gprof2dot
python -m cProfile -o profile.pstats mine.py
gprof2dot -f pstats profile.pstats | dot -Tsvg -o mine.svg
@Макси'комментарий этот ответ помогли мне достаточно того, что я думаю, что это заслуживает своего собственного ответа: я уже cProfile автоматически .файлы pstats и я вовсе'т хотите, чтобы повторно запустить вещи с pycallgraph, так что я использовал gprof2dot, и получил довольно свгс:
$ sudo apt-get install graphviz
$ git clone https://github.com/jrfonseca/gprof2dot
$ ln -s "$PWD"/gprof2dot/gprof2dot.py ~/bin
$ cd $PROJECT_DIR
$ gprof2dot.py -f pstats profile.pstats | dot -Tsvg -o callgraph.svg
и Блам!
Он использует точка (то же самое, что pycallgraph использует) так что вывод похож. Я получаю впечатление, что gprof2dot хотя и теряет меньше информации:
Я побежал в удобный инструмент под названием SnakeViz при исследовании этой темы. SnakeViz-это веб-инструмент профилирования визуализации. Это очень легко установить и использовать. Обычным способом я использую это, чтобы создать файл стат с %Прун
и затем сделать анализ в SnakeViz.
Основной используемый метод именно солнечные лучи диаграммы как показано ниже, в которой иерархия вызовов функций в виде слоев дуг и время, закодированное в их угловой шириной.
Самое лучшее, что вы можете взаимодействовать с диаграммой. Например, для увеличения можно кликнуть по дуге, и дуга, и его потомки будут увеличены как новый санберст, чтобы отобразить больше деталей.
Я думаю, что cProfile
отлично подходит для профилирования, а программа
отлично подходит для визуализации результатов. В pyprof2calltree
между ручками преобразование файла.
python -m cProfile -o script.profile script.py
pyprof2calltree -i script.profile -o script.calltree
kcachegrind script.calltree
Чтобы установить необходимые инструменты (в Ubuntu, по крайней мере):
apt-get install kcachegrind
pip install pyprof2calltree
Результат:
Также стоит отметить просмотрщик графический интерфейс дамп cProfile RunSnakeRun. Это позволяет сортировать и отбирать, тем самым увеличив соответствующих частей программы. Размеры прямоугольников на рисунке пропорциональна времени. При наведении указателя мыши на прямоугольник, он подчеркивает, что призыв в таблице и везде на карте. Когда вы дважды щелкните на прямоугольнике она фокусируется на этой части. Он покажет вам, кто называет эту часть и то, что часть звонков.
Описательная информация очень полезная. Он показывает вам код, что немного что может быть полезно, когда вы имеете дело со встроенным библиотечные вызовы. Он говорит вам, что файл и какие строки, чтобы найти код.
Также хочу указать на то, что ОП сказал, 'профилирования' но, похоже, он имел в виду 'время'. Имейте в виду программы будут работать медленнее, когда профнастил.
Простой и быстрый как найти, где все время идет.
1. pip install snakeviz
2. python -m cProfile -o temp.dat <PROGRAM>.py
3. snakeviz temp.dat
Рисует круговую диаграмму в браузере. Большой кусок-это функция проблем. Очень просто.
Хороший модуль профилирования является line_profiler (вызывается с помощью kernprof.py сценарий). Его можно скачать здесь.
Мое понимание заключается в том, что cProfile только дает информацию о общее время, проведенное в каждой функции. Поэтому отдельные строки кода не приурочен. Это вопрос в научных вычислений, поскольку часто одной линии может занять много времени. Также, насколько я помню, cProfile не'т поймать время я проводил в сказать и NumPy.точка.
line_profiler
(уже представлены) также вдохновил pprofile
, которая описывается как:
линии детализации, поток детерминированный и статистический чистом Python профайлер
Это обеспечивает линейный детализации как line_profiler
, это на чистом Python, могут быть использованы в качестве самостоятельной команды или модуль, и даже может создать callgrind-формат файлов, которые могут быть легко проанализированы с [К|М]модулем cachegrind
.
Существует также vprof, пакет python, описанный как:
[...] обеспечивая богатый и интерактивных визуализаций для различных характеристик программы на Python, таких как время выполнения и использование памяти.
Недавно я создал тунец для визуализации в Python runtime и импортных профилей; это может быть полезным здесь.
Установить с
pip3 установить тунца
Создании профиля во время выполнения
питон -mcProfile -о программе.проф yourfile.py
или импортировать профиль (в Python 3.7+ требуется)
питон -х importprofile yourfile.py 2 и GT; импорт.журнал
Затем просто запустите тунец на файл
программа тунец.проф
Там'ы много хороших ответов, но они либо использовать командную строку или какие-то внешние программы для профилирования и/или сортировки результатов.
Я действительно пропустил какой-то способ я могу использовать в моей среде 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)
См. документы или другие ответы, для получения дополнительной информации.
После Джо шо'ы ответ о многопоточный код не работает должным образом, я поняла, что runcallметод cProfile просто делать самостоятельно.включить()
и самостоятельно.отключить()
звонки по всему профилированного вызова функции, так что вы можете просто сделать это самостоятельно, и иметь все, что код, который вы хотите, в-Между, с минимальным вмешательством в существующий код.
В источнике Virtaal'а есть очень полезный класс и декоратор, который может очень легко сделать профилирование (даже для конкретных методов/функций). Полученные результаты можно очень удобно просматривать в KCacheGrind.
cProfile отлично подходит для быстрого профилирования, но большую часть времени он заканчивается для меня с ошибками. Runctx функция решает эту проблему путем инициализации корректно окружающей среды и переменных, надеюсь, что это может быть полезно для кого-то:
import cProfile
cProfile.runctx('foo()', None, locals())
Мой способ заключается в использовании яппи (https://code.google.com/p/yappi/). Это's особенно полезен в сочетании с сервером 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
(или изменить ЭКП способ, чтобы вернуть его к абоненту) и получите такой результат:
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
метод может быть вызван несколько раз с течением времени в профиле и сравнить, например, различные сценарии использования программы.
Если вы хотите сделать накопительный профилировщик, смысл, чтобы запустить функцию несколько раз подряд и наблюдайте, как сумма результатов.
вы можете использовать этот cumulative_profiler` декоратор:
это'ы на Python >= 3.6 конкретные, но вы можете удалить "нелокального" для его работать на старых версиях.
import cProfile, pstats
class _ProfileFunc:
def __init__(self, func, sort_stats_by):
self.func = func
self.profile_runs = []
self.sort_stats_by = sort_stats_by
def __call__(self, *args, **kwargs):
pr = cProfile.Profile()
pr.enable() # this is the profiling section
retval = self.func(*args, **kwargs)
pr.disable()
self.profile_runs.append(pr)
ps = pstats.Stats(*self.profile_runs).sort_stats(self.sort_stats_by)
return retval, ps
def cumulative_profiler(amount_of_times, sort_stats_by='time'):
def real_decorator(function):
def wrapper(*args, **kwargs):
nonlocal function, amount_of_times, sort_stats_by # for python 2.x remove this row
profiled_func = _ProfileFunc(function, sort_stats_by)
for i in range(amount_of_times):
retval, ps = profiled_func(*args, **kwargs)
ps.print_stats()
return retval # returns the results of the function
return wrapper
if callable(amount_of_times): # incase you don't want to specify the amount of times
func = amount_of_times # amount_of_times is the function in here
amount_of_times = 5 # the default amount
return real_decorator(func)
return real_decorator
Пример
профилирующая функция баз
import time
@cumulative_profiler
def baz():
time.sleep(1)
time.sleep(2)
return 1
baz()
баз
бежал 5 раз и напечатал:
20 function calls in 15.003 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
10 15.003 1.500 15.003 1.500 {built-in method time.sleep}
5 0.000 0.000 15.003 3.001 <ipython-input-9-c89afe010372>:3(baz)
5 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
указание количества раз
@cumulative_profiler(3)
def baz():
...
Чтобы добавить на 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 о том, как смысла собираемой статистики.
Новый инструмент для обработки профилирования в Python-это PyVmMonitor: http://www.pyvmmonitor.com/
Он имеет некоторые уникальные особенности, такие как
Примечание: это's коммерческих, но бесплатно с открытым исходным кодом.