Когда оптимизация не преждевременна и, следовательно, не является злом?


75

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



Ответы:


116

Когда вы основываете это на опыте? Не зло «Каждый раз, когда мы делали X, мы терпели жестокий удар по производительности. Давайте на этот раз планируем либо оптимизировать, либо полностью избегать X».

Когда это относительно безболезненно? Не зло «Реализация этого как Foo или Bar займет столько же работы, но теоретически Bar должен быть намного более эффективным. Давайте Bar это».

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

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


Steve314 и Matthieu M. поднимают вопросы в комментариях, которые следует рассмотреть. По сути, некоторые разновидности «безболезненных» оптимизаций просто не стоят того, потому что предлагаемое ими тривиальное обновление производительности не стоит запутывания кода, они дублируют улучшения, которые уже выполняет компилятор, или и то, и другое. Посмотрите комментарии для некоторых хороших примеров слишком хитрых половинных улучшений.


22
Иногда легко решить проблему с фантомом - это все же слегка зло, поскольку это может привести к тому, что будет труднее читать, труднее поддерживать код. Не намного сложнее (или это не будет легким решением), но, возможно, иногда все еще актуально. Примером может быть использование хитрого побитового трюка, который некоторые люди не узнают, и который компилятор, вероятно, в любом случае будет применять, если это будет полезно.
Steve314

26
Я согласен со Стивом здесь, иногда «оптимизация» просто не стоит того, особенно потому, что компиляторы чертовски хороши. Пример ? если iне подписано, i / 2может быть заменено на i >> 1. Это быстрее. Но это также более загадочно (не все увидят эффект, даже те, кто это делает, могут потерять время). Но хуже всего то, что компилятор все равно это сделает, так зачем запутывать исходный код;)?
Матье М.

19
@Larry: я не сделал, так что я думаю, что это хороший пример.
Йорис Мейс

18
На мой взгляд, оптимизация, даже простая, также должна рассматриваться как зло, если она влияет на читаемость / сопровождение кода и не основана на фактических измерениях производительности.
Барт ван Инген Шенау

14
@ Матфея: научить их чему? Грязные и ненужные трюки? Почему? Если профилирование показывает, что a i/2действительно является горячей точкой и что (невероятно, но давайте предположим) i>>1делает это быстрее, то сделайте это и добавьте комментарий, чтобы это профилирование показало, что это быстрее. Если это действительно нужно где-то (что я сомневаюсь, так как, как сказал Матье, компиляторы должны быть достаточно умными, чтобы сделать это сами), новички узнают что-то, если это не так (что вероятно), почему вы хотите подключить их головы с ненужным фольклором?
ВОО

38

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

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


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

1
Извините, но "быть хорошим во всех аспектах" звучит подозрительно, как переобучение. Кроме того, это, вероятно, нереально - жизнь всегда связана с компромиссами.
слеске

1
+1 за акцент на этапе проектирования; если вы намеренно взвешиваете его преимущества, это не преждевременно.
Натан Тагги

И наоборот, если вы никогда не знаете, как будет использоваться ваша библиотека, вы не знаете, имеет ли какое-либо деловое значение затрачивание времени на ее улучшение. Так что это вряд ли аргумент.
RemcoGerlich

25

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

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


17

Когда оптимизация не преждевременна и, следовательно, не является злом?

Трудно сказать, что такое добро и зло. У кого есть это право? Если мы посмотрим на природу, кажется, что мы запрограммированы на выживание с широким определением «выживания», которое включает передачу наших генов потомству.

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

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


3
Приятно видеть, как кто-то приносит свежий взгляд на этот старый каштан. Все, что нужно, это прочитать всю цитату Кнута, а не только одно предложение, а?
Роберт Харви

1
@RobertHarvey У меня там есть немного любопытства, потому что многие, похоже, цитируют только одно предложение, и так много важной контекстной информации теряется в процессе. Я не уверен, что это такой хороший ответ, так как я получил небольшую награду. :-D

14

Полная цитата определяет , когда оптимизация не преждевременно:

Такие рассуждения не приведут к самоуспокоенности хорошего программиста, он посмотрит внимательно на критический код; но только после того, как этот код был идентифицирован . [Акцент мой]

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


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

11

Вы должны всегда выбирать «достаточно хорошее» решение во всех случаях, основываясь на вашем опыте.

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

Это означает, что вам не следует выбирать суперкомплекс «сортировать файлы по 100 ГБ путем прозрачной загрузки на диск», когда будет выполнять простую сортировку, но вы также должны сначала сделать хороший выбор для простой сортировки. Слепой выбор Bubble Sort или «выбрать все записи случайным образом и посмотреть, в порядке ли они. Повторите.» редко бывает хорошим


3

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


3

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

Также важно знать, где именно узкое место в производительности - оптимизация части кода, которая занимает всего 5% от общего времени выполнения, не принесет пользы.

Шаги 2 и 3 описывают преждевременную оптимизацию:

  1. Сделай так, чтобы это работало
  2. Контрольная работа. Не достаточно быстро? Профиль это .
  3. Используя данные из шага 2, оптимизируйте самые медленные части кода.

Вы забыли шаг 0, а именно: правильно спроектируйте приложение, чтобы с самого начала ожидать разумной производительности.
Роберт Харви

Я говорил только о подробном этапе реализации.
Горги Косев

1
Я задаю вопрос на шаге 3 - очень часто лучшим ответом является выяснение другого подхода, чтобы вы не делали медленный кусок кода в первую очередь.
Лорен Печтел

1
Выберите правильные структуры данных.
Джейсон

3

Это не оптимизация при выборе вещей, которые трудно изменить, например: аппаратная платформа.

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


3

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

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

Кто-то сказал: сначала сделай это правильно, а потом сделай это быстро. Они были правы.

Но теперь для кикера: если вы сделали это несколько раз, вы узнаете глупые вещи, которые вы делали ранее, которые вызывают проблемы со скоростью, поэтому вы инстинктивно избегаете их. (Такие вещи, как создание слишком тяжелой структуры вашего класса, заваление уведомлениями, смешение размера вызовов функций с их стоимостью времени, список можно продолжать и продолжать ...) Вы инстинктивно избегаете этого, но догадаетесь, как это выглядит для менее опытный: преждевременная оптимизация!

Так что эти глупые дебаты продолжаются и продолжаются :)

** Еще одна вещь, которую они говорят, это то, что вам больше не нужно об этом беспокоиться, потому что компиляторы такие хорошие, а машины такие быстрые в наше время. (KIWI - Kill It With Iron.) Не существует экспоненциального аппаратного или системного ускорения (выполненного очень умными трудолюбивыми инженерами), которое могло бы компенсировать экспоненциальное замедление программного обеспечения (созданное программистами, которые так думают).


2

Когда требования или рынок специально просит об этом.

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

Другим примером могут быть некоторые типы встроенных устройств. Взять, к примеру, тормоз ABS; Во-первых, существует безопасность, когда вы попадаете в перерыв, машина должна замедляться. Но есть и производительность, вы не хотели бы никаких задержек, когда вы выходите на перерыв.


0

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

Примеры из реального мира.

  • Если для выполнения моей сортировки пузырьков требуется 20 мс, оптимизация до быстрой сортировки 1 мс не приведет к значительному повышению общей полезности, несмотря на увеличение производительности на 2000%.

  • Если загрузка веб-страницы занимает 20 секунд, а мы уменьшаем ее до 1 секунды, это может увеличить полезность веб-сайта с 0 до бесконечности. В основном то, что было сломано, потому что это было слишком медленно, теперь полезно.


Важно отметить, что если ваш сорт вызывается 1000 раз в течение вашей программы, оптимизация от 20 мс до 1 мс является большой проблемой.
Бифстер

0

Какой вид оптимизации не является преждевременным?

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

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

(то есть это не так - «Я думаю, что этот фрагмент кода выглядит медленным, я заменю X на Y вместо этого, и это будет быстрее»).

Я столкнулся с множеством преждевременных «оптимизаций», которые в конечном итоге сделали код медленнее - в данном случае я считаю преждевременным значение «не продумано». Производительность должна оцениваться до и после оптимизации, и должен сохраняться только тот код, который действительно улучшает производительность.


0

«Преждевременная оптимизация - корень всего зла» - это то, что почти все мы слышали / читали

Правда. К сожалению, это также одна из самых (злонамеренно) неправильно используемых программных цитат всех времен. Поскольку Дональд Кнут создал мем, стоит добавить оригинальный контекст из цитаты:

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

Обратите внимание, что Кнут говорил конкретно о скорости выполнения во время выполнения .

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

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

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

Как я уже говорил ранее, «преждевременная оптимизация» является одним из наиболее злонамеренно неправильно используемых мемов, поэтому ответ не будет полным без некоторых примеров вещей, которые не являются преждевременной оптимизацией, но иногда игнорируются как таковые:

  • узкие места, которые видны невооруженным глазом и которых можно избежать, прежде чем вводить их, например, O (N ^ 2) количество обращений в базу данных с большим N, где существует альтернатива O (1)

Далее даже не связаны со скоростью выполнения во время выполнения:

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.