Ускорение Python

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

  • в первую очередь: Если у вас уже есть проект на Python, какие есть достойные способы его ускорить, помимо простой оптимизации в коде?

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

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

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
44
0
21 537
18

Ответы 18

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

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

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

+1 Я только что попробовала психо, и это потрясающе! Невероятно простой в использовании и невероятно эффективный (YMMV, см. Веб-сайт)

Davide 14.05.2009 03:04

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

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

Что, если основные узкие места связаны с библиотечными функциями, которые уже написаны в оптимизированном стиле C типа NumPy?

ely 13.09.2012 16:58

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

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

В 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 - если они отличаются, должно быть очень легко выяснить, что не так, и исправить проблему.

Конкатенация строк не так уж плоха в Python 2.5. Точка данных на генераторах: 2: 1 (v2.5.2), 1,5: 1,5 (v3.0) - список против генераторов для ресурсоемкой функции, которую я тестировал вчера (то есть производительность такая же на py3k, генераторы не работают на v2.5)

jfs 06.10.2008 04:41

Чтобы добавить к этому комментарию: причина того, что конкатенация строк не так уж плоха в 2.5 (и 2.6), заключается в том, что в CPython есть специальная оптимизация для этого случая (но не обязательно любая другая реализация Python).

Tony Meyer 06.10.2008 08:44

Тони, не могли бы вы предоставить подробную информацию об оптимизации?

Seun Osewa 03.02.2009 20:52

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

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

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

Приведенный выше комментарий имеет смысл только в том случае, если вы по какой-то причине не можете использовать psyco и pyrex. (Pyrex - это особенно простой способ скомпилировать большинство функций языка Python до кода C и объявить переменные, типы которых совместимы с типами C, так что они будут обрабатываться как таковые в скомпилированном коде.)

Alex Coventry 06.10.2008 03:03

Alex, psyco и pyrex не дают вам решения Общее для c-подобной скорости сейчас, и, возможно, никогда не дойдут до него. При этом слишком беспокоиться о скорости выполнения часто плохо: преждевременная оптимизация. Если у вас знать, он вам нужен, c часто является лучшим способом добиться этого в python.

simon 06.10.2008 06:58

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

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

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

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

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

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

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

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

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

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

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

Нижняя граница

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

@AbidRahmanK Это на archive.org: web.archive.org/web/20101225202706/http://www.cs.cmu.edu/~jc‌ h /…

Tobias Kienzler 10.08.2012 18:28

Я удивлен, что никто не упомянул 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

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

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

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

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

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

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

Я думаю, что в настоящее время к этому биту с числами следует добавить панд (pandas.pydata.org).

moooeeeep 03.04.2013 21:26

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

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

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

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

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

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

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

Помимо (отличного) Psyco и (хорошего) шкура, я бы порекомендовал попробовать Cython, отличный форк пирекс.

Или, если вы никуда не торопитесь, рекомендую просто подождать. Появляются новые виртуальные машины на Python, и незагруженная ласточка найдет свое место в мейнстриме.

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

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

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

Вот несколько советов: http://blog.hackerearth.com/faster-python-code

Другие вопросы по теме