Должен ли я оптимизировать свой код Python, как C ++? Это имеет значение? - PullRequest
5 голосов
/ 30 августа 2009

Я поспорил с коллегой об эффективном написании Python. Он утверждал, что, хотя вы программируете на python, вам все же нужно максимально оптимизировать небольшие кусочки программного обеспечения, как если бы вы писали эффективный алгоритм на C ++.

Такие вещи, как:

  • В операторе if с or всегда ставится условие, наиболее вероятное сбой первого, поэтому второе проверяться не будет.
  • Используйте наиболее эффективные функции для работы со строками общего пользования. Не код, который размалывает строки, а простые вещи, такие как объединение и разбиение и поиск подстрок.
  • Вызывайте как можно меньше функций, даже если это происходит за счет читабельности, из-за накладных расходов, которые это создает.

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

Как вы относитесь к этому вопросу?

Ответы [ 10 ]

14 голосов
/ 30 августа 2009

Мой ответ на это будет:

Мы должны забыть о маленьких эффективность, скажем, около 97% время: преждевременная оптимизация корень зла.

(Цитата: Кнут, Дональд. Структурированное программирование с переходом к заявлениям, ACM Journal Computing Surveys, том 6, № 4, декабрь 1974. с.268)


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

А если работать после таких выступлений, то почему бы не написать код на языке ассемблера? Потому что Python легче / быстрее писать и поддерживать? Ну, если это так, вы правы: -)

Самое главное, что ваш код прост в обслуживании; не пара микросекунд процессорного времени!
Ну, может быть, кроме случаев, когда у вас есть тысячи серверов - но разве это ваш случай?

13 голосов
/ 30 августа 2009

Ответ действительно прост:

  • Следуйте рекомендациям Python, а не C ++.
  • Читаемость в Python важнее скорости.
  • Если производительность становится проблемой, измерьте, а затем приступайте к оптимизации.
10 голосов
/ 30 августа 2009

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

По сути, вам нужно подумать о возврате инвестиций. Стоит ли дополнительных усилий при чтении и поддержании «оптимизированного» кода в течение пары микросекунд, которые он спасает вас? В большинстве случаев это не так.

(Кроме того, компиляторы и среды выполнения становятся все умнее. Некоторые микрооптимизации могут со временем стать микропессимизациями.)

4 голосов
/ 30 августа 2009

Я согласен с другими: сначала читаемый код («Производительность не проблема, пока производительность не проблема.»).

Я только хочу добавить, что когда вам абсолютно необходимо написать какой-то нечитаемый и / или неинтуитивный код, вы, как правило, можете выделить его несколькими специальными методами, для которых вы можете написать подробные комментарии и сохранить остальную часть кода. очень удобочитаемый Если вы сделаете это, у вас будет простой в обслуживании код, и вам придется проходить нечитаемые части только тогда, когда вам это действительно нужно.

3 голосов
/ 30 августа 2009

Я должен также сказать, что контекст кода не является сверхэффективным NOC или системами наведения ракет. В основном мы пишем тесты на python.

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

2 голосов
/ 31 августа 2009

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

Тогда, если вы действительно хотите встать на путь оптимизации, вы должны сначала научиться измерять и профилировать. Оптимизация ДОЛЖНА БЫТЬ КОЛИЧЕСТВЕННОЙ - не идти вразрез. Профилировщик точек доступа покажет вам функции, в которых ваша программа чаще всего перегорает.

Если оптимизация включает такую ​​функцию, ее часто называют:

def get_order_qty(ordernumber):
    # look up order in database and return quantity

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

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

(Кстати, это действительно то, что вы имели в виду? • В операторе if с условием или всегда ставить условие, вероятнее всего, не выполненное первым, поэтому второе проверяться не будет.

Мне следует подумать, что это может иметь место для «и», но «или» замкнет накоротко, если первое значение равно True, сохраняя оценку второго слагаемого условия. Поэтому я бы изменил это правило оптимизации на:

  • Если вы проверяете "A и B", сначала ставьте A, если более вероятно, чтобы оценить
    Ложные.
  • Если проверяется "A или B", сначала ставьте A, если это более вероятно, чтобы оценить Правда.

Но часто последовательность условий определяется самими тестами:

if obj is not None and hasattr(obj,"name") and obj.name.startswith("X"):

Вы не можете переупорядочить их для оптимизации - они имеют в этом порядке (или просто позволяют исключениям вылетать и ловить их позже:

if obj.name.startswith("X"):
2 голосов
/ 30 августа 2009

Я думаю, что здесь есть несколько связанных «городских легенд».

  • Неверно Помещение наиболее часто проверяемого условия в условную и аналогичные оптимизации экономит достаточно времени для типичной программы, которое того стоит для типичного программиста.

  • Верно Некоторые, но не многие, люди используют такие стили в Python из-за неверного мнения, изложенного выше.

  • True Многие люди используют такой стиль в Python, когда думают, что он улучшает читаемость программы Python.

О читабельности: я думаю, что это действительно полезно, когда вы сначала даете наиболее полезные условные выражения, поскольку в любом случае это то, что люди сначала замечают. Вам также следует использовать ''.join(), если вы имеете в виду конкатенацию строк, поскольку это самый прямой способ сделать это (операция s += x может означать что-то другое).

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

2 голосов
/ 30 августа 2009

В операторе if с или всегда ставь условие скорее всего не получится во-первых, поэтому второго не будет проверено.

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

Используйте наиболее эффективные функции для манипулирование строками общего пользования. Не код, который размалывает строки, но простые вещи, как делать соединения и разбивает и находит подстроки.

Я действительно не понимаю этого. Конечно, вы должны использовать предоставляемые библиотекой функции, потому что они, вероятно, реализованы на C, а реализация на чистом Python, скорее всего, будет медленнее. В любом случае не нужно изобретать велосипед.

Вызовите как можно меньше функций, даже если это происходит за счет удобочитаемость, из-за накладных расходов это создает.

$ cat withcall.py
def square(a):
        return a*a

for i in xrange(1,100000):
        i_square = square(i)

$ cat withoutcall.py
for i in xrange(1,100000):
        i_square = i*i

$ time python2.3 withcall.py
real    0m5.769s
user    0m4.304s
sys     0m0.215s
$ time python2.3 withcall.py
real    0m5.884s
user    0m4.315s
sys     0m0.206s

$ time python2.3 withoutcall.py
real    0m5.806s
user    0m4.172s
sys     0m0.209s
$ time python2.3 withoutcall.py
real    0m5.613s
user    0m4.171s
sys     0m0.216s

Я имею в виду ... давай ... пожалуйста.

1 голос
/ 31 августа 2009

Моя внутренняя реакция такова:

Я работал с такими парнями, как твой коллега, и вообще я бы не советовался с ними.

Спросите его, использовал ли он когда-либо профиль.

1 голос
/ 30 августа 2009

Конечно, следуйте лучшим практикам Python (и на самом деле я согласен с первыми двумя рекомендациями), но ремонтопригодность и эффективность не противоположны, они в основном вместе (если это слово).

Утверждения, такие как «всегда писать свои операторы IF определенным способом для повышения производительности», являются априорными, то есть не основаны на знании того, на что ваша программа тратит время, и, следовательно, являются догадками. Первое (или второе, или третье, что угодно) правило настройки производительности: не догадываюсь .

Если после измерения, профиля или в моем случае сделать это , вы на самом деле знаете , что вы можете сэкономить много времени путем повторного заказа тестов, во что бы то ни стало, делайте. Мои деньги говорят, что это на уровне 1% или меньше.

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