×
Traktatov.net » Язык программирования Python » Читать онлайн
Страница 135 из 141 Настройки

>     28317   1.590   0.000   1.590   0.000 difflib.py:344(find_longest_match)

>      6474   0.100   0.000   2.690   0.000 difflib.py:454(get_matching_blocks)

>28317/6190   1.000   0.000   2.590   0.000 difflib.py:480(__helper)

>      6474   0.450   0.000   3.480   0.001 difflib.py:595(ratio)

>     28686   0.240   0.000   0.240   0.000 difflib.py:617()

>    158345   8.690   0.000   9.760   0.000 difflib.py:621(quick_ratio)

>    159442   2.950   0.000   4.020   0.000 difflib.py:650(real_quick_ratio)

>         1   4.930   4.930  23.610  23.610 difflib.py:662(get_close_matches)

>         1   0.010   0.010  23.620  23.620 profile:0(print_close_matches("профайлер"))

>         0   0.000   0.000                 profile:0(profiler)

Здесь колонки таблицы показывают следующие значения: ncalls — количество вызовов (функции), tottime — время выполнения кода функции (не включая времени выполнения вызываемых из нее функций), percall — то же время, в пересчете на один вызов, cumtime — суммарное время выполнения функции (и всех вызываемых из нее функций), filename — имя файла, lineno — номер строки в файле, function — имя функции (если эти параметры известны).

Из приведенной статистики следует, что наибольшие усилия по оптимизации кода необходимо приложить в функциях >quick_ratio() (на нее потрачено 8,69 секунд), >get_close_matches() (4,93 секунд), затем можно заняться >real_quick_ratio() (2,95 секунд) и >_calculate_ratio() (секунд).

Это лишь самый простой вариант использования профайлера: модуль >profile (и связанный с ним >pstats) позволяет получать и обрабатывать статистику: их применение описано в документации.

Модуль timeit

Предположим, что проводится оптимизация небольшого участка кода. Необходимо определить, какой из вариантов кода является наиболее быстрым. Это можно сделать с помощью модуля >timeit.

В следующей программе используется метод >timeit() для измерения времени, необходимого для вычисления небольшого фрагмента кода. Измерения проводятся для трех вариантов кода, делающих одно и то же: конкатенирующих десять тысяч строк в одну строку. В первом случае используется наиболее естественный, «лобовой» прием инкрементной конкатенации, во втором — накопление строк в списке с последующим объединением в одну строку, в третьем применяется списковое включение, а затем объединение элементов списка в одну строку:

>from timeit import Timer


>t = Timer("""

>res = ""

>for k in range(1000000,1010000):

> res += str(k)

>""")

>print t.timeit(200)


>t = Timer("""

>res = []

>for k in range(1000000,1010000):

> res.append(str(k))

>res = ",".join(res)

>""")

>print t.timeit(200)


>t = Timer("""

>res = ",".join([str(k) for k in range(1000000,1010000)])

>""")

>print t.timeit(200)

Разные версии Python дадут различные результаты прогонов:

># Python 2.3

>77.6665899754

>10.1372740269

>9.07727599144


># Python 2.4

>9.26631307602

>9.8416929245

>7.36629199982

В старых версиях Python рекомендуемым способом конкатенации большого количества строк являлось накопление их в списке с последующим применением функции >join() (кстати, инкрементная конкатенация почти в восемь раз медленнее этого приема). Начиная с версии 2.4, инкрементная конкатенация была оптимизирована и теперь имеет даже лучший результат, чем версия со списками (которая вдобавок требует больше памяти). Но чемпионом все–таки является работа со списковым включением, поэтому свертывание циклов в списковое включение позволяет повысить эффективность кода.