Ускорение Питона - PullRequest
       68

Ускорение Питона

42 голосов
/ 06 октября 2008

Это на самом деле два вопроса, но они очень похожи, и для простоты я решил, что я просто свожу их вместе:

  • Во-первых : Принимая во внимание устоявшийся проект на Python, какие есть приличные способы ускорить его помимо простой оптимизации в коде?

  • Во-вторых : Каковы хорошие способы значительно повысить производительность при написании программы на python?

Что касается первого вопроса, представьте, что вы получили достойно написанный проект, и вам нужно улучшить производительность, но вы не можете получить большую выгоду за счет рефакторинга / оптимизации. Что бы вы сделали, чтобы ускорить его в этом случае, за исключением переписывания чего-то вроде C?

Ответы [ 18 ]

41 голосов
/ 06 октября 2008

Относительно "Во-вторых: при написании программы с нуля на python, какие есть хорошие способы значительно повысить производительность?"

Запомните правила оптимизации Джексона:

  • Правило 1: не делай этого.
  • Правило 2 (только для экспертов): пока не делайте этого.

И правило Кнута:

  • «Преждевременная оптимизация - корень всего зла».

Более полезные правила содержатся в Общих правилах оптимизации .

  1. Не оптимизируйте по ходу дела. Сначала поймите правильно. Тогда сделай это быстро. Оптимизация неправильной программы по-прежнему не так.

  2. Помните правило 80/20.

  3. Всегда запускайте тесты «до» и «после». В противном случае вы не узнаете, нашли ли вы 80%.

  4. Используйте правильные алгоритмы и структуры данных. Это правило должно быть первым. Ничто так не важно, как алгоритм и структура данных.

Итог

Вы не можете предотвратить или избежать попытки «оптимизировать эту программу». Это часть работы. Вы должны планировать это и делать это тщательно, точно так же, как дизайн, код и действия по тестированию.

26 голосов
/ 06 октября 2008

Вместо того, чтобы просто драться до C, я бы предложил:

Сделайте ваш счетчик кодов. Делайте больше с меньшим количеством исполнений строк:

  • Изменить алгоритм на более быстрый. Во многих случаях это не должно быть модным, чтобы быть быстрее.
  • Используйте python-примитивы, написанные на C. Некоторые вещи заставят переводчика отправиться туда, где некоторые не захотят. Последний предпочтительнее
  • Остерегайтесь кода, который сначала создает большую структуру данных, а затем использует ее. Подумайте о разнице между диапазоном и xrange. В общем, часто стоит задуматься об использовании памяти программой. Использование генераторов может иногда снизить использование памяти O (n) до O (1).
  • Python обычно не оптимизируется. Поднимайте инвариантный код из циклов, по возможности исключайте общие подвыражения в тесных циклах.
  • Если что-то дорогое, то предварительно вычислите или запомните это. Например, регулярные выражения могут быть скомпилированы.
  • Нужно хрустить числами? Вы можете проверить numpy.
  • Многие программы на Python работают медленно, потому что они связаны с дисковым вводом-выводом или доступом к базе данных. Убедитесь, что у вас есть что-то стоящее, пока вы ожидаете получения данных, а не просто блокируете. Оружие может быть чем-то вроде Twisted framework.
  • Обратите внимание, что многие важные библиотеки обработки данных имеют C-версии, будь то XML, JSON или еще много чего. Они часто значительно быстрее, чем интерпретатор Python.

Если все вышеперечисленное не сработало для профилированного и измеренного кода, тогда подумайте о пути перезаписи C.

23 голосов
/ 06 октября 2008

Обычные подозреваемые - профилируйте это, найдите самую дорогую линию, выясните, что она делает, исправьте это. Если вы раньше не выполняли много профилирования, могут быть большие жирные квадратичные циклы или дублирование строк, скрывающиеся за другими безобидно выглядящими выражениями.

В Python две наиболее распространенные причины неявного замедления, которые я обнаружил, - это конкатенация строк и генераторы. Поскольку строки Python являются неизменяемыми, выполните что-то вроде этого:

result = u""
for item in my_list:
    result += unicode (item)

скопирует всю строку дважды за итерацию. Это было хорошо освещено, и решение состоит в том, чтобы использовать "".join:

result = "".join (unicode (item) for item in my_list)

Генераторы - еще один преступник. Они очень просты в использовании и могут значительно упростить некоторые задачи, но плохо примененный генератор будет намного медленнее, чем просто добавление элементов в список и его возврат.

Наконец, не бойтесь переписывать биты в C! Python, как динамический язык высокого уровня, просто не способен соответствовать скорости Си. Если есть одна функция, которую вы больше не можете оптимизировать в Python, рассмотрите возможность ее извлечения в модуль расширения.

Моя любимая техника для этого - поддерживать версии модуля на Python и C. Версия Python написана так, чтобы быть максимально понятной и очевидной - любые ошибки должны легко диагностироваться и исправляться. Напишите свои тесты против этого модуля. Затем напишите версию C и протестируйте ее. Его поведение во всех случаях должно быть таким же, как и в реализации Python - если они различаются, должно быть очень легко выяснить, что является неправильным, и исправить проблему.

17 голосов
/ 06 октября 2008

Первое, что приходит на ум: psyco . Пока работает только на x86.

Тогда константное связывание . То есть, сделать все глобальные ссылки (и global.attr , global.attr.attr …) локальными именами внутри функций и методов. Это не всегда успешно, но в целом это работает. Это можно сделать вручную, но, очевидно, это утомительно.

Вы сказали, что помимо оптимизации внутри кода, я не буду вдаваться в подробности, но держу ваш разум открытым для типичных ошибок (for i in range(10000000) приходит на ум), которые совершают люди.

9 голосов
/ 06 октября 2008

Cython и pyrex могут использоваться для генерации кода c с использованием Python-подобного синтаксиса. Psyco также отлично подходит для подходящих проектов (иногда вы не заметите большого увеличения скорости, иногда это будет в 50 раз быстрее). Я все еще считаю, что лучший способ - профилировать ваш код (cProfile и т. Д.), А затем просто кодировать узкие места как функции c для python.

7 голосов
/ 06 октября 2008

Я удивлен, что никто не упомянул ShedSkin: http://code.google.com/p/shedskin/, он автоматически конвертирует вашу программу на Python в C ++ и в некоторых тестах дает лучшие улучшения по скорости, чем psyco.

Плюс анекдотичные истории о простоте: http://pyinsci.blogspot.com/2006/12/trying-out-latest-release-of-shedskin.html

Существуют ограничения, пожалуйста, смотрите: http://tinyurl.com/shedskin-limitations

5 голосов
/ 13 декабря 2008

Надеюсь, вы прочитали: http://wiki.python.org/moin/PythonSpeed/PerformanceTips

Возобновление того, что уже есть, обычно 3 принципа:

  • написать код, который преобразуется в более качественный байт-код, например, использовать местные, избегать ненужных поисков / вызовов, использовать идиоматические конструкции (если есть естественный синтаксис для того, что вы хотите, используйте его - обычно быстрее. для ввода ключа some_dict.keys () ", do" для ввода ключа some_dict ")
  • все, что написано на C, значительно быстрее, злоупотребляйте любыми имеющимися у вас функциями / модулями C
  • если есть сомнения, время импорта, профиль
4 голосов
/ 06 октября 2008

Это не обязательно ускорит любой ваш код, но является критическим знанием при программировании на Python, если вы хотите избежать замедления вашего кода. «Глобальная блокировка интерпретатора» (GIL) может значительно снизить скорость вашей многопоточной программы, если ее поведение не понято (да, это немного меня ... У меня была хорошая 4-процессорная машина, которая не будет использовать более 1,2 процессоров одновременно). Есть вводная статья с некоторыми ссылками, чтобы вы начали с SmoothSpan .

4 голосов
/ 06 октября 2008

Люди дали несколько полезных советов, но вы должны знать, что когда требуется высокая производительность, модель python выглядит следующим образом: pnt to c. Такие усилия, как psyco, могут в будущем немного помочь, но python просто не быстрый язык, и он не предназначен для этого. Очень немногие языки способны действительно хорошо выполнять динамические вещи и все же генерировать очень быстрый код; по крайней мере, в обозримом будущем (и некоторые проекты работают против быстрой компиляции), что будет иметь место.

Итак, если вы действительно окажетесь в этой привязке, вам лучше всего будет изолировать части вашей системы, которые недопустимо медленны в (хорошем) питоне, и разработать идею, что вы переписываете эти биты в C . Сожалею. Хороший дизайн может помочь сделать это менее болезненным. Прототипируйте его сначала в python, а затем вы легко можете проверить работоспособность вашего c.

Это работает достаточно хорошо для таких вещей, как numpy, в конце концов. Хотя я не могу особо подчеркнуть, насколько хороший дизайн поможет вам. Если вы просто итеративно тыкаете в свои биты Python и заменяете самые медленные на C, у вас может получиться большой беспорядок. Подумайте, где именно нужны биты C, и как их можно минимизировать и разумно инкапсулировать.

4 голосов
/ 06 октября 2008

Запустите ваше приложение через профилировщик Python. Найти серьезное узкое место. Перепишите это узкое место на C. Повторите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...