Когда оптимизация преждевременна? - PullRequest
77 голосов
/ 22 декабря 2008

Как сказал Кнут,

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

Это то, что часто встречается в ответах Stack Overflow на такие вопросы, как «какой механизм цикла является наиболее эффективным», «Методы оптимизации SQL?» ( и т. Д. ). Стандартный ответ на эти вопросы по оптимизации состоит в том, чтобы сначала профилировать свой код и посмотреть, если это сначала проблема, а если нет, то, следовательно, ваша новая техника не нужна.

У меня вопрос: если конкретный метод отличается, но не особенно неясен или не запутан, может ли это считаться преждевременной оптимизацией?

Вот статья Рэндалла Хайда по теме Ошибка преждевременной оптимизации .

Ответы [ 20 ]

100 голосов
/ 22 декабря 2008

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

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

  • Использование арифметики указателей вместо обозначения массива в C, включая использование таких идиом, как

    for (p = q; p < lim; p++)
    
  • Связывание глобальных переменных с локальными переменными в Lua, как в

    local table, io, string, math
        = table, io, string, math
    

Помимо таких идиом, используйте ярлыки на свой страх и риск .

Вся оптимизация преждевременна, если

  • Программа работает слишком медленно (многие люди забывают эту часть).

  • У вас есть измерение (профиль или подобное), показывающее, что оптимизация может улучшить положение вещей .

(также допустимо оптимизировать для памяти.)

Прямой ответ на вопрос:

  • Если ваша «другая» техника затрудняет понимание программы , то преждевременная оптимизация .

EDIT : В ответ на комментарии с использованием быстрой сортировки вместо более простого алгоритма, такого как сортировка вставок , является еще одним примером идиомы, которую все понимают и ожидают . (Хотя если вы пишете свою собственную процедуру сортировки вместо использования библиотечной процедуры сортировки, можно надеяться, что у вас есть очень веская причина.)

40 голосов
/ 22 декабря 2008

ИМХО, 90% вашей оптимизации должно происходить на этапе проектирования, исходя из воспринимаемого тока и, что более важно, будущих требований. Если вам нужно удалить профилировщик, потому что ваше приложение не масштабируется до требуемой нагрузки, вы оставили его слишком поздно, и IMO потратит много времени и усилий, не решив проблему.

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

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

29 голосов
/ 22 декабря 2008

Если вы не профилировали, это преждевременно.

27 голосов
/ 22 декабря 2008

Мой вопрос, если конкретный техника отличается, но не особенно неясный или запутанный, это действительно можно считать преждевременная оптимизация?

Гм ... Итак, у вас есть две готовые методики, одинаковые по стоимости (одинаковые усилия по использованию, чтению, изменению) и одна более эффективная. Нет, в этом случае использование более эффективного не было бы преждевременным.

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

9 голосов
/ 24 ноября 2009

Вот проблема, которую я вижу со всей концепцией предотвращения преждевременной оптимизации.

Существует разрыв между тем, чтобы говорить это и делать это.

Я много настраивал производительность, вытесняя важные факторы из хорошо спроектированного кода, казалось бы, без преждевременной оптимизации. Вот пример.

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

А в учебном материале, где преподаются эти абстрактные концепции проектирования, такие как архитектура на основе уведомлений и сокрытие информации, где простая установка логического свойства объекта может иметь неограниченный волновой эффект от деятельности, какова причина этого ? Эффективность .

Итак, это была преждевременная оптимизация или нет?

8 голосов
/ 22 декабря 2008

Во-первых, получите работающий код. Во-вторых, убедитесь, что код правильный. В-третьих, сделай это быстро.

Любой код изменить , который выполняется до этапа № 3, безусловно, преждевременно. Я не совсем уверен, как классифицировать варианты дизайна, сделанные до этого (например, использование хорошо подходящих структур данных), но я предпочитаю ориентироваться на использование абстракций, с которыми легко программировать, а не с теми, которые хорошо работают, пока я этап, на котором я могу начать использовать профилирование и иметь правильную (хотя и часто медленную) эталонную реализацию для сравнения результатов с.

7 голосов
/ 22 декабря 2008

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

Тип оптимизации, о которой говорит правило Кнута, заключается в минимизации длины наиболее распространенных путей кода, оптимизации кода, который выполняется чаще всего, например, переписыванием в сборке или упрощением кода, что делает его менее общим. Но делать это бесполезно до тех пор, пока вы не будете уверены, какие части кода нуждаются в такой оптимизации, и оптимизация сделает (может?) Затруднить понимание или поддержание кода, поэтому «преждевременная оптимизация - корень всех зол».

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

В ответ на множество других комментариев по этому вопросу: алгоритм выбора! = Оптимизация

6 голосов
/ 22 декабря 2008

С точки зрения базы данных, не принимать во внимание оптимальный дизайн на этапе проектирования, в лучшем случае безрассудно. Базы данных не легко рефакторинг. Как только они плохо спроектированы (это то, что дизайн, который не учитывает оптимизацию, не имеет значения, как вы можете попытаться спрятаться за бессмысленной преждевременной оптимизацией), почти никогда не сможет восстановиться после этого, поскольку база данных слишком базова работа всей системы. Гораздо менее затратно спроектировать правильно с учетом оптимального кода для ожидаемой ситуации, чем ждать, пока миллионы пользователей и люди кричат, потому что вы использовали курсоры во всем приложении. Другие оптимизации, такие как использование sargeable кода, выбор наилучших возможных индексов и т. Д., Имеют смысл делать только во время разработки. Есть причина, почему быстрая и грязная называется так. Потому что он никогда не будет работать хорошо, поэтому не используйте быстроту вместо хорошего кода. Также, откровенно говоря, когда вы понимаете настройку производительности в базах данных, вы можете написать код, который с большей вероятностью будет работать хорошо в то же время или меньше, чем требуется для написания кода, который не работает хорошо. Не тратить время на то, чтобы понять, как хорошо работает дизайн базы данных, это лень для разработчиков, а не передовой опыт.

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

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

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

4 голосов
/ 25 декабря 2008

Оптимизация может происходить на разных уровнях детализации, от очень высокого уровня до очень низкого уровня:

  1. Начните с хорошей архитектуры, слабой связи, модульности и т. Д.

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

  3. Оптимизация для памяти, пытаясь разместить больше кода / данных в кеше. Подсистема памяти работает в 10-100 раз медленнее, чем центральный процессор, а если ваши данные переносятся на диск, это в 1000-10000 раз медленнее. Осторожность в отношении потребления памяти, скорее всего, даст большую выгоду, чем оптимизация отдельных инструкций.

  4. В каждой функции используйте соответствующие операторы управления потоком. (Переместите неизменяемые выражения за пределы тела цикла. Сначала укажите наиболее распространенное значение в переключателе / ​​регистре и т. Д.)

  5. В каждом утверждении используйте наиболее эффективные выражения, дающие правильный результат. (Умножение на сдвиг и т. Д.)

Проницательный выбор того, использовать ли выражение деления или выражение сдвига, не является обязательно преждевременной оптимизацией. Это преждевременно, если вы сделаете это без предварительной оптимизации архитектуры, структур данных, алгоритмов, использования памяти и управления потоком.

И, конечно, любая оптимизация преждевременна, если вы не определили порог достижения цели.

В большинстве случаев либо:

A) Вы можете достичь целевого порога производительности, выполняя высокоуровневые оптимизации, поэтому нет необходимости возиться с выражениями.

или

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

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

...