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






Первое, что приходит в голову: Psyco. Пока он работает только на x86.
Затем постоянная привязка. То есть сделайте все глобальные ссылки (и global.attr, global.attr.attr…) локальными именами внутри функций и методов. Это не всегда удается, но в целом работает. Это можно сделать вручную, но, очевидно, это утомительно.
Вы сказали, помимо оптимизации кода, поэтому я не буду вдаваться в подробности, но помните о типичных ошибках (на ум приходит for i in range(10000000)), которые делают люди.
Это не обязательно ускорит какой-либо ваш код, но очень важно знать при программировании на Python, если вы хотите избежать замедления вашего кода. «Глобальная блокировка интерпретатора» (GIL) может значительно снизить скорость вашей многопоточной программы, если ее поведение непонятно (да, это меня утомило ... У меня была хорошая четырехпроцессорная машина, которая не использовать более 1,2 процессора одновременно). Есть вводная статья с некоторыми ссылками, чтобы вы начали работу с SmoothSpan.
Запустите приложение через профилировщик Python. Найдите серьезное узкое место. Перепишите это узкое место на C. Повторить.
Что, если основные узкие места связаны с библиотечными функциями, которые уже написаны в оптимизированном стиле C типа NumPy?
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)
Чтобы добавить к этому комментарию: причина того, что конкатенация строк не так уж плоха в 2.5 (и 2.6), заключается в том, что в CPython есть специальная оптимизация для этого случая (но не обязательно любая другая реализация Python).
Тони, не могли бы вы предоставить подробную информацию об оптимизации?
Люди дали несколько хороших советов, но вы должны знать, что, когда требуется высокая производительность, модель python: punt to c. Такие усилия, как psyco, могут в будущем немного помочь, но python просто не быстрый язык, и он не предназначен для этого. Очень немногие языки обладают способностью действительно хорошо выполнять динамические функции и при этом генерировать очень быстрый код; по крайней мере, в обозримом будущем (а некоторые конструкции работают против быстрой компиляции) так и будет.
Итак, если вы действительно оказались в этой привязке, лучше всего будет изолировать части вашей системы, которые неприемлемо медленны в (хорошем) питоне, и спроектировать их вокруг идеи, что вы переписываете эти биты на C. Извините. Хороший дизайн поможет сделать это менее болезненным. Однако сначала создайте прототип на python, затем вы легко сможете проверить работоспособность и на вашем c.
В конце концов, это работает достаточно хорошо для таких вещей, как numpy. Я не могу переоценить, насколько хороший дизайн вам поможет. Если вы просто итеративно протыкаете свои биты Python и заменяете самые медленные на C, вы можете получить большой беспорядок. Подумайте, где именно нужны C-биты, и как их можно разумно минимизировать и инкапсулировать.
Приведенный выше комментарий имеет смысл только в том случае, если вы по какой-то причине не можете использовать psyco и pyrex. (Pyrex - это особенно простой способ скомпилировать большинство функций языка Python до кода C и объявить переменные, типы которых совместимы с типами C, так что они будут обрабатываться как таковые в скомпилированном коде.)
Alex, psyco и pyrex не дают вам решения Общее для c-подобной скорости сейчас, и, возможно, никогда не дойдут до него. При этом слишком беспокоиться о скорости выполнения часто плохо: преждевременная оптимизация. Если у вас знать, он вам нужен, c часто является лучшим способом добиться этого в python.
Просто примечание об использовании psyco: в некоторых случаях он может действительно приводить к более медленному времени выполнения. Особенно при попытке использовать psyco с кодом, написанным на C. Я не могу вспомнить статью, которую я читал, но функции map() и reduce() были упомянуты специально. К счастью, вы можете указать psyco не обрабатывать указанные функции и / или модули.
Относительно «Во-вторых: при написании программы с нуля на Python, каковы несколько хороших способов значительно улучшить производительность?»
Помните правила оптимизации Джексона:
И правило Кнута:
Более полезные правила находятся в Общие правила оптимизации.
Не оптимизируйте на ходу. Сначала сделай это правильно. Тогда сделай это быстро. Оптимизировать неправильную программу все равно неправильно.
Помните правило 80/20.
Всегда выполняйте тесты «до» и «после». В противном случае вы не узнаете, нашли ли вы 80%.
Используйте правильные алгоритмы и структуры данных. Это правило должно быть первым. Нет ничего важнее алгоритма и структуры данных.
Нижняя граница
Вы не можете предотвратить или избежать попытки «оптимизировать эту программу». Это часть работы. Вы должны спланировать это и делать это осторожно, как и действия по дизайну, программированию и тестированию.
@AbidRahmanK Это на archive.org: web.archive.org/web/20101225202706/http://www.cs.cmu.edu/~jc h /…
Я удивлен, что никто не упомянул 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
Это процедура, которой я стараюсь следовать:
Вместо того, чтобы просто переходить к C, я бы посоветовал:
Сделайте свой код значимым. Делайте больше с меньшим количеством выполнений строк:
numpy.Twisted.Если все вышеперечисленное не подходит для профилированного и измеренного кода, подумайте о пути C-rewrite.
Я думаю, что в настоящее время к этому биту с числами следует добавить панд (pandas.pydata.org).
Если вы используете 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
Возобновление того, что уже есть, обычно основывается на трех принципах:
Помимо (отличного) Psyco и (хорошего) шкура, я бы порекомендовал попробовать Cython, отличный форк пирекс.
Или, если вы никуда не торопитесь, рекомендую просто подождать. Появляются новые виртуальные машины на Python, и незагруженная ласточка найдет свое место в мейнстриме.
После того, как был задан этот вопрос, были предложены несколько способов ускорить код Python:
Я считаю, что для уже существующего проекта основной выигрыш в производительности будет за счет максимального использования внутренней библиотеки python.
Вот несколько советов: http://blog.hackerearth.com/faster-python-code
+1 Я только что попробовала психо, и это потрясающе! Невероятно простой в использовании и невероятно эффективный (YMMV, см. Веб-сайт)