Оптимизация производительности

Введение

Примеры

  • 2

    Профилирование кода

    Прежде всего вы должны быть в состоянии найти узкое место в вашем скрипте и заметить, что никакая оптимизация не может компенсировать плохой выбор в структуре данных или недостаток в вашем алгоритме. Во-вторых, не пытайтесь оптимизировать процесс кодирования слишком рано в ущерб удобочитаемости / дизайну / качеству. Дональд Кнут сделал следующее заявление об оптимизации:

    «Мы должны забыть о малой эффективности, скажем, в 97% случаев: преждевременная оптимизация - корень всего зла. Но мы не должны упускать наши возможности в эти критические 3%»

    Для профилирования кода у вас есть несколько инструментов: cProfile (или медленнее , в profile ) из стандартной библиотеки, line_profiler и timeit . Каждый из них служит своей цели.

    cProfile является determistic профилировщика: вызов функции, обратные функции, а также исключение события контролируются, и точные тайминги сделаны для интервалов между этими событиями (до 0.001s). Документация библиотеки ( https://docs.python.org/2/library/profile.html ) дает нам простой прецеденту

     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 ) полезно иметь линию по анализу линии вашего кода. Это явно не поддается управлению длинными сценариями, но нацелено на фрагменты кода. Смотрите документацию для более подробной информации. Самый простой способ начать работу - использовать скрипт 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 обеспечивает простой способ проверить один лайнеры или небольшое выражение как из командной строки и питон оболочки. Этот модуль будет отвечать на такие вопросы , как, это быстрее , чтобы сделать список понимание или использовать встроенный в 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
    
    

Синтаксис

Параметры

Примечания