Python Language
Оптимизация производительности
Поиск…
замечания
При попытке улучшить производительность скрипта Python, прежде всего, вы должны найти узкое место вашего сценария и отметить, что никакая оптимизация не может компенсировать плохой выбор структур данных или недостаток в разработке вашего алгоритма. Определение узких мест производительности может быть выполнено путем профилирования вашего скрипта. Во-вторых, не пытайтесь оптимизировать слишком рано в процессе кодирования за счет удобочитаемости / дизайна / качества. Дональд Кнут сделал следующее заявление об оптимизации:
«Мы должны забыть о небольшой эффективности, скажем, около 97% времени: преждевременная оптимизация - корень всего зла. Но мы не должны упускать наши возможности в этих критических 3% ».
Профилирование кода
Прежде всего, вы должны найти узкое место вашего сценария и отметить, что никакая оптимизация не может компенсировать плохой выбор структуры данных или недостаток в дизайне вашего алгоритма. Во-вторых, не пытайтесь оптимизировать слишком рано в процессе кодирования за счет удобочитаемости / дизайна / качества. Дональд Кнут сделал следующее заявление об оптимизации:
«Мы должны забыть о небольшой эффективности, скажем, примерно в 97% случаев: преждевременная оптимизация - это корень всего зла, но мы не должны упускать наши возможности в этих критических 3%
Для cProfile
вашего кода у вас есть несколько инструментов: cProfile
(или более медленный profile
) из стандартной библиотеки, line_profiler
и timeit
. Каждый из них служит другой цели.
cProfile
- это детерминированный профилировщик: отслеживаются вызов функции, возврат функции и события исключения, а также точные тайминги для интервалов между этими событиями (до 0,001 с). Документация библиотеки ([ https://docs.python.org/2/library/profile.html][1]) предоставляет нам простой пример использования
import cProfile
def f(x):
return "42!"
cProfile.run('f(12)')
Или, если вы предпочитаете обертывать части вашего существующего кода:
import cProfile, pstats, StringIO
pr = cProfile.Profile()
pr.enable()
# ... do something ...
# ... long ...
pr.disable()
sortby = 'cumulative'
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats()
print s.getvalue()
Это создаст результаты, похожие на таблицу ниже, где вы сможете быстро увидеть, где ваша программа проводит большую часть своего времени, и определить функции для оптимизации.
3 function calls in 0.000 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 <stdin>:1(f)
1 0.000 0.000 0.000 0.000 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
Модуль line_profiler
([ https://github.com/rkern/line_profiler][1]) полезен для линейного анализа вашего кода. Очевидно, что это невозможно для длинных скриптов, но нацелено на фрагменты. Дополнительную информацию см. В документации. Самый простой способ начать - использовать скрипт kernprof, как описано на странице пакета, обратите внимание, что вам нужно будет вручную указать функцию (функции) для профиля.
$ kernprof -l script_to_profile.py
kernprof создаст экземпляр LineProfiler и вставляет его в пространство имен __builtins__
с профилем имени. Он был написан для использования в качестве декоратора, поэтому в вашем скрипте вы украшаете функции, которые хотите профилировать с помощью @profile
.
@profile
def slow_function(a, b, c):
...
Поведение kernprof по умолчанию заключается в том, чтобы поместить результаты в двоичный файл script_to_profile.py.lprof
. Вы можете сказать kernprof немедленно просмотреть отформатированные результаты на терминале с опцией [-v / - view]. В противном случае вы можете просмотреть результаты позже так:
$ python -m line_profiler script_to_profile.py.lprof
Наконец, timeit
предоставляет простой способ протестировать один лайнер или небольшое выражение как из командной строки, так и из оболочки python. Этот модуль ответит на вопрос, например: быстрее ли выполнять понимание списка или использовать встроенный list()
при преобразовании набора в список. Найдите ключевое слово setup
или -s
чтобы добавить установочный код.
>>> import timeit
>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
0.8187260627746582
от терминала
$ python -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 40.3 usec per loop