Ускорение Python

На самом деле это два вопроса, но они настолько похожи, и чтобы все было просто, я подумал, что просто сверну их:

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

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

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

Ответ 1

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

Помните правила оптимизации Jackson:

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

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

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

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

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

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

  • Всегда выполняйте тесты "до" и "после". В противном случае вы не узнаете, нашли ли вы 80%.

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

Нижняя строка

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

Ответ 2

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

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

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

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

Ответ 3

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

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

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

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

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

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

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

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

Ответ 4

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

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

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

Ответ 5

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

Ответ 6

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

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

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

Ответ 7

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

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

  • писать код, который преобразуется в лучший байт-код, например, использовать локали, избегать ненужных поисков/вызовов, использовать идиоматические конструкции (если есть естественный синтаксис для того, что вы хотите, использовать его - обычно быстрее, например: не делать: для ключа в some_dict.keys() ", выполните" для ключа в some_dict ")
  • все, что написано на C, значительно быстрее, злоупотребляет любыми C функциями/модулями, которые у вас есть.
  • если есть сомнения, import timeit, profile

Ответ 8

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

Ответ 9

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

Ответ 10

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

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

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

Ответ 11

Только примечание об использовании psyco: в некоторых случаях это может привести к более медленному времени выполнения. Особенно при попытке использовать psyco с кодом, написанным на C. Я не могу вспомнить статью, которую я прочитал, но функции map() и reduce() были упомянуты конкретно. К счастью, вы можете сказать psyco не обрабатывать определенные функции и/или модули.

Ответ 12

Это процедура, которую я пытаюсь выполнить:

  •  
  • import psyco; psyco.full()  
  • Если это не достаточно быстро, запустите код через профайлер, посмотрите, где узкие места. (ОТКЛЮЧАЙТЕ psyco для этого шага!)  
  • Попробуйте сделать такие вещи, как упомянутые другие люди, чтобы как можно быстрее получить код на этих узких местах.  
    • Такие вещи, как [str (x) для x в l] или [x.strip() для x в l], намного, намного медленнее, чем map (str, x) или map (str.strip, x).
     
  • После этого, если мне все еще нужно больше скорости, на самом деле очень легко получить PyRex и запустить его. Сначала я копирую раздел кода python, помещаю его непосредственно в код pyrex и вижу, что происходит. Затем я общаюсь с ним, пока он не станет быстрее и быстрее.

Ответ 13

Часто бывает возможно достичь почти C-скоростей (достаточно близко для любого проекта с использованием Python в первую очередь!), заменив явные алгоритмы, написанные в Python с помощью неявного алгоритма, используя встроенный вызов Python. Это работает, потому что большинство встроенных модулей Python написаны на C в любом случае. Ну, в CPython, конечно;-) https://www.python.org/doc/essays/list2str/

Ответ 14

Каноническая ссылка на то, как улучшить код Python, приведена здесь: PerformanceTips. Я бы рекомендовал не оптимизировать C, если вам это действительно нужно. Для большинства приложений вы можете получить необходимую производительность, следуя правилам, опубликованным в этой ссылке.

Ответ 15

Если вы используете psyco, я бы рекомендовал psyco.profile() вместо psyco.full(). Для более крупного проекта он будет более умным в отношении функций, которые были оптимизированы, и использовать тонну меньше памяти.

Я бы также рекомендовал посмотреть итераторы и генераторы. Если ваше приложение использует большие наборы данных, это избавит вас от многих копий контейнеров.

Ответ 16

Помимо (отличного) psyco и (nice) shedskin, я рекомендую попробовать cython отличную вилку pyrex.

Или, если вы не спешите, я рекомендую просто подождать. Появляются новые виртуальные машины python, и unladen-swallow найдет свой путь в основной поток.

Ответ 17

После этого вопроса были предложены несколько способов ускорения кода Python:

  • Pypy имеет JIT-компилятор, что делает его намного быстрее для кода с привязкой к процессору.
  • Pypy написано в Rpython, подмножестве Python, который компилируется в собственный код, используя инструмент LLVM - цепь.

Ответ 18

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

Некоторые советы здесь: http://blog.hackerearth.com/faster-python-code