Как сказал Кнут,
Мы должны забыть о небольшой эффективности, скажем, примерно в 97% случаев: преждевременная оптимизация - это корень всех зол.
Это то, что часто возникает в ответах на вопросы Stack Overflow на такие вопросы, как «какой механизм цикла является наиболее эффективным», «методы оптимизации SQL?» ( и так далее ). Стандартный ответ на эти вопросы с советами по оптимизации - профилировать ваш код и сначала посмотреть, не проблема, а если нет, то ваша новая техника не нужна.
Мой вопрос: если конкретная техника отличается, но не является особенно неясной или запутанной, может ли это действительно считаться преждевременной оптимизацией?
Вот статья Рэндалла Хайда «Ошибка преждевременной оптимизации» .
Ответы:
Дон Кнут начал движение за грамотное программирование, потому что он считал, что самая важная функция компьютерного кода - передать намерения программиста человеческому читателю . Любая практика кодирования, которая затрудняет понимание вашего кода во имя производительности, является преждевременной оптимизацией.
Некоторые идиомы, которые были введены во имя оптимизации, стали настолько популярными, что их все понимают, и они стали ожидаемыми , а не преждевременными. Примеры включают
Использование арифметики указателей вместо записи массива в C, включая использование таких идиом, как
Повторная привязка глобальных переменных к локальным переменным в Lua, как в
Помимо таких идиом, сокращайте путь на свой страх и риск .
Вся оптимизация преждевременна, если только
Программа слишком медленная (многие забывают эту часть).
У вас есть измерение (профиль или подобное), показывающее, что оптимизация может улучшить ситуацию .
(Также допустима оптимизация для памяти.)
Прямой ответ на вопрос:
РЕДАКТИРОВАТЬ : В ответ на комментарии использование быстрой сортировки вместо более простого алгоритма, такого как сортировка вставкой, является еще одним примером идиомы, которую все понимают и ожидают . (Хотя, если вы напишете свою собственную процедуру сортировки вместо использования процедуры сортировки библиотеки, можно надеяться, что у вас есть очень веская причина.)
источник
ИМХО, 90% вашей оптимизации должно происходить на стадии проектирования, исходя из текущих и, что более важно, будущих требований. Если вам нужно удалить профилировщик, потому что ваше приложение не масштабируется до требуемой нагрузки, вы оставили его слишком поздно, и IMO потратит много времени и усилий, не сумев исправить проблему.
Как правило, целесообразны только те оптимизации, которые позволяют на порядок повысить производительность с точки зрения скорости или множителя с точки зрения хранилища или пропускной способности. Эти типы оптимизации обычно относятся к выбору алгоритма и стратегии хранения, и их чрезвычайно сложно отменить в существующий код. Они могут настолько серьезно повлиять на решение о языке, на котором вы реализуете свою систему.
Итак, мой совет: оптимизируйте как можно раньше, исходя из ваших требований, а не кода, и смотрите на возможное продление срока службы вашего приложения.
источник
while (s[0]==' ') s = s.substring(1)
for(i=0; i<s.len && s[i]==' '; ++i); s=s.substring(i)
- но для этого уже необходимо знать потенциальные проблемы с производительностью (профилировщики - ценные инструменты для постоянного обучения здесь).Если вы не профилировали, это преждевременно.
источник
Гм ... Итак, у вас есть две готовые техники, одинаковые по стоимости (одинаковые усилия для использования, чтения, изменения), и одна более эффективна. Нет, в таком случае не было бы преждевременным использование более эффективного.
Прерывание написания кода для поиска альтернатив распространенным программным конструкциям / библиотечным подпрограммам на случай, если где-то есть более эффективная версия, хотя, насколько вам известно, относительная скорость того, что вы пишете, никогда не будет иметь значения. .. Это преждевременно.
источник
Вот проблема, которую я вижу во всей концепции предотвращения преждевременной оптимизации.
Есть разрыв между тем, чтобы сказать это и сделать это.
Я проделал большую настройку производительности, выжимая большие факторы из хорошо спроектированного кода, казалось бы, без преждевременной оптимизации. Вот вам пример.
Почти в каждом случае причиной неоптимальной производительности является то, что я называю стремительной общностью , то есть использование абстрактных многослойных классов и тщательного объектно-ориентированного проектирования, где простые концепции были бы менее элегантными, но полностью достаточными.
И в учебном материале, где преподаются эти абстрактные концепции дизайна, такие как архитектура, управляемая уведомлениями, и скрытие информации, где простая установка логического свойства объекта может иметь неограниченный волновой эффект действий, какова причина? Эффективность .
Так это была преждевременная оптимизация или нет?
источник
Во-первых, заставьте код работать. Во-вторых, убедитесь, что код правильный. В-третьих, сделайте это быстро.
Любое изменение кода , которое производится до этапа № 3, безусловно, преждевременно. Я не совсем уверен, как классифицировать выбор дизайна, сделанный до этого (например, с использованием хорошо подходящих структур данных), но я предпочитаю отклоняться в сторону использования абстракций, с которыми легко программировать, а не с теми, которые хорошо работают, пока я не достигну этап, на котором я могу начать использовать профилирование и иметь правильную (хотя часто медленную) эталонную реализацию для сравнения результатов.
источник
С точки зрения базы данных, не рассматривать оптимальный дизайн на этапе проектирования в лучшем случае безрассудно. Базы данных не так легко реорганизовать. Если они плохо спроектированы (это то, что дизайн, который не учитывает оптимизацию, независимо от того, как вы могли бы попытаться спрятаться за ерундой преждевременной оптимизации), почти никогда не сможет восстановиться от этого, потому что база данных слишком проста для работа всей системы. Гораздо менее затратно правильно спроектировать с учетом оптимального кода для ожидаемой ситуации, чем ждать, пока не появится миллион пользователей и люди будут кричать, потому что вы использовали курсоры во всем приложении. Другие оптимизации, такие как использование расширяемого кода, выбор наиболее подходящих индексов и т. Д., Имеют смысл только во время разработки. Не зря так называется «быстро и грязно». Потому что он никогда не может хорошо работать, поэтому не используйте скорость вместо хорошего кода. Кроме того, откровенно говоря, когда вы понимаете настройку производительности в базах данных, вы можете написать код, который с большей вероятностью будет работать хорошо за то же время или меньше, чем требуется для написания кода, который не работает хорошо. Не тратить время на изучение того, что лучше всего работает при проектировании базы данных, - это лень разработчика, а не лучшая практика.
источник
Кажется, вы говорите об оптимизации, такой как использование контейнера поиска на основе хэша, против индексированного, такого как массив, когда будет выполнено много ключевых поисков. Это не преждевременная оптимизация, это то, что вы должны решить на этапе проектирования.
Тип оптимизации, о которой идет речь в правиле Кнута, - это минимизация длины наиболее распространенных кодовых путей, оптимизация кода, который чаще всего выполняется, например, путем переписывания на ассемблере или упрощения кода, делая его менее общим. Но делать это бесполезно, пока вы не будете уверены, какие части кода нуждаются в такой оптимизации, а оптимизация (может?) Затруднит понимание или поддержку кода, следовательно, «преждевременная оптимизация - корень всех зол».
Кнут также говорит, что всегда лучше вместо оптимизации изменить алгоритмы, которые использует ваша программа, и подход, который она принимает к проблеме. Например, если небольшая настройка может дать вам 10% -ное увеличение скорости с оптимизацией, фундаментальное изменение способа работы вашей программы может сделать ее в 10 раз быстрее.
В ответ на множество других комментариев по этому вопросу: выбор алгоритма! = Оптимизация
источник
Суть максимы состоит в том, что обычно оптимизация запутана и сложна. И обычно вам, архитектору / дизайнеру / программисту / сопровождающему, нужен ясный и лаконичный код, чтобы понять, что происходит.
Если конкретная оптимизация ясна и лаконична, не стесняйтесь экспериментировать с ней (но вернитесь и проверьте, эффективна ли эта оптимизация). Смысл в том, чтобы код оставался ясным и кратким на протяжении всего процесса разработки, пока преимущества производительности не перевесят затраты на написание и поддержку оптимизаций.
источник
Я пытаюсь оптимизировать только тогда, когда подтверждается проблема с производительностью.
Мое определение преждевременной оптимизации - это «потраченные впустую усилия на код, который, как известно, не снижает производительности». Определенно есть время и место для оптимизации. Однако хитрость заключается в том, чтобы потратить дополнительные затраты только там, где они имеют значение для производительности приложения и где дополнительные затраты перевешивают снижение производительности.
При написании кода (или запроса к БД) я стремлюсь написать «эффективный» код (т.е. код, который выполняет свою предполагаемую функцию, быстро и полностью с разумной простейшей логикой). Обратите внимание, что «эффективный» код не обязательно совпадает с «оптимизированным». код. Оптимизация часто вносит дополнительную сложность в код, что увеличивает стоимость разработки и сопровождения этого кода.
Мой совет: старайтесь оплачивать оптимизацию только тогда, когда вы можете количественно оценить выгоду.
источник
При программировании большое значение имеет ряд параметров. Среди них:
Оптимизация (стремление к производительности) часто происходит за счет других параметров и должна быть сбалансирована с «потерями» в этих областях.
Когда у вас есть возможность выбрать хорошо известные алгоритмы, которые работают хорошо, затраты на предварительную «оптимизацию» часто являются приемлемыми.
источник
Оптимизация может происходить на разных уровнях детализации, от очень высокого до очень низкого:
Начните с хорошей архитектуры, слабой связи, модульности и т. Д.
Выберите правильные структуры данных и алгоритмы для решения проблемы.
Оптимизируйте для памяти, пытаясь уместить больше кода / данных в кеш. Подсистема памяти в 10-100 раз медленнее, чем ЦП, а если ваши данные выгружаются на диск, это в 1000-10 000 раз медленнее. Осторожность с потреблением памяти с большей вероятностью принесет большую пользу, чем оптимизация отдельных инструкций.
Внутри каждой функции надлежащим образом используйте операторы управления потоком. (Переместите неизменяемые выражения за пределы тела цикла. Поместите наиболее распространенное значение первым в переключателе / регистре и т. Д.)
Внутри каждого оператора используйте наиболее эффективные выражения, дающие правильный результат. (Умножение против сдвига и т. Д.)
Принятие решения о том, следует ли использовать выражение деления или выражение сдвига, не обязательно преждевременная оптимизация. Это преждевременно, если вы сделаете это без предварительной оптимизации архитектуры, структур данных, алгоритмов, объема памяти и управления потоком.
И, конечно, любая оптимизация будет преждевременной, если вы не определите порог эффективности.
В большинстве случаев либо:
A) Вы можете достичь целевого порога производительности, выполнив высокоуровневую оптимизацию, поэтому нет необходимости возиться с выражениями.
или же
Б) Даже после выполнения всех возможных оптимизаций вы не достигнете своего целевого порога производительности, а низкоуровневые оптимизации не повлияют на производительность настолько, чтобы оправдать потерю читаемости.
По моему опыту, большинство проблем оптимизации можно решить либо на уровне архитектуры / дизайна, либо на уровне структуры данных / алгоритма. Часто (хотя и не всегда) требуется оптимизация использования памяти. Но оптимизировать логику управления потоком и выражений требуется редко. А в тех случаях, когда это действительно необходимо, этого редко бывает достаточно.
источник
Норман ответил превосходно. Каким-то образом вы регулярно делаете некоторую «преждевременную оптимизацию», что на самом деле является наилучшей практикой, потому что, как известно, делать иначе, как известно, совершенно неэффективно.
Например, чтобы добавить в список Нормана:
for (i = 0; i < strlen(str); i++)
(потому что здесь strlen - это вызов функции, каждый раз проходящий по строке, вызываемый в каждом цикле);for (i = 0 l = str.length; i < l; i++)
и он все еще читается, так что хорошо.И так далее. Но такие микрооптимизации никогда не должны происходить за счет читабельности кода.
источник
Необходимость использования профилировщика следует оставить на крайний случай. Инженеры проекта должны знать, где есть узкие места в производительности.
Я думаю, что «преждевременная оптимизация» невероятно субъективна.
Если я пишу код и знаю что мне следует использовать Hashtable, я это сделаю. Я не буду реализовывать его каким-либо некорректным образом, а затем ждать отчета об ошибке через месяц или год, когда у кого-то возникнут проблемы.
Редизайн обходится дороже, чем оптимизация дизайна очевидными способами с самого начала.
Очевидно, что некоторые мелочи будут упущены с первого раза, но они редко являются ключевыми дизайнерскими решениями.
Следовательно: НЕ оптимизация дизайна - это ИМО, запах кода сам по себе.
источник
Стоит отметить, что оригинальная цитата Кнута взята из статьи, которую он написал, продвигая использование
goto
в тщательно выбранных и измеренных областях как способ устранения горячих точек. Его цитата была предостережением, которое он добавил, чтобы оправдать его использованиеgoto
для ускорения этих критических циклов.И продолжает:
Не забывайте, как он использовал слово «оптимизировано» в кавычках (программное обеспечение, вероятно, на самом деле неэффективно). Также обратите внимание на то, как он критикует не только этих глупых программистов, но и людей, которые в ответ предлагают вам всегда игнорировать мелкие недостатки. Наконец, к часто цитируемой части:
... а затем еще немного о важности инструментов профилирования:
Люди повсюду злоупотребляли его цитатой, часто предполагая, что микрооптимизации преждевременны, когда вся его статья пропагандировала микрооптимизации! Одна из групп людей, которых он критиковал, которые повторяют эту «общепринятую точку зрения», поскольку он всегда игнорирует эффективность в малом, часто неправильно используют его цитату, которая первоначально была направлена, отчасти, против таких людей, которые препятствуют всем формам микрооптимизации. .
Тем не менее, это была цитата в пользу правильно примененных микрооптимизаций при использовании опытным человеком, держащим профилировщик. Сегодняшний аналогичный эквивалент может выглядеть так: «Людям не следует слепо пытаться оптимизировать свое программное обеспечение, но настраиваемые распределители памяти могут иметь огромное значение при применении в ключевых областях для улучшения локальности ссылок» или « Рукописный код SIMD с использованием SoA rep действительно сложно поддерживать, и вы не должны использовать его повсюду, но он может потреблять память намного быстрее, если применять его соответствующим образом опытной и управляемой рукой ».
Каждый раз, когда вы пытаетесь продвигать тщательно применяемые микрооптимизации, как продвигал Кнут выше, полезно сделать заявление об отказе от ответственности, чтобы не дать новичкам слишком волноваться и вслепую пытаться оптимизировать, например, переписывать все свое программное обеспечение для использования
goto
. Отчасти это он и делал. Его цитата фактически была частью большого отказа от ответственности, точно так же, как кто-то, прыгая на мотоцикле через пылающую костровую яму, может добавить отказ от ответственности, что любители не должны пробовать это дома, одновременно критикуя тех, кто пытается без надлежащих знаний и оборудования и получает травму. .То, что он считал «преждевременной оптимизацией», было оптимизацией, применявшейся людьми, которые фактически не знали, что они делают: не знали, действительно ли оптимизация нужна, не измеряли с помощью соответствующих инструментов, возможно, не понимали природу их компилятор или компьютерная архитектура, и, что самое главное, были «глупыми на копейки и фунтами», то есть они упустили из виду большие возможности оптимизации (сэкономить миллионы долларов), пытаясь скупить копейки, и все время при создании кода они не могли дольше эффективно отлаживать и поддерживать.
Если вы не попадаете в категорию «глупых и глупых», то вы не преждевременно оптимизируете по стандартам Кнута, даже если вы используете
goto
, чтобы ускорить критический цикл (что маловероятно чтобы сильно помочь против сегодняшних оптимизаторов, но если бы это было так, и в действительно критической области, то вы не стали бы преждевременно оптимизировать). Если вы действительно применяете то, что делаете, в тех областях, которые действительно необходимы, и они действительно получают от этого выгоду, то в глазах Кнута вы делаете просто отлично.источник
Для меня преждевременная оптимизация означает попытку повысить эффективность вашего кода до того, как у вас будет рабочая система, и до того, как вы действительно профилируете ее и не узнаете, где находится узкое место. Даже после этого во многих случаях удобочитаемость и ремонтопригодность должны предшествовать оптимизации.
источник
Я не думаю, что признанные передовые практики - это преждевременная оптимизация. Это больше касается времени на то, что, если, то есть потенциальных проблем с производительностью в зависимости от сценариев использования. Хороший пример: если вы потратите неделю, пытаясь оптимизировать отражение над объектом, прежде чем у вас будет доказательство того, что это узкое место, вы преждевременно оптимизируете.
источник
Если вы не обнаружите, что вам требуется более высокая производительность вашего приложения в связи с потребностями пользователя или бизнеса, нет особых причин беспокоиться об оптимизации. Даже в этом случае ничего не делайте, пока не профилируете свой код. Затем атакуйте те части, на которые уходит больше всего времени.
источник
На мой взгляд, если вы оптимизируете что-то, не зная, сколько производительности вы можете получить в другом сценарии, это преждевременная оптимизация. Цель кода действительно должна сделать его максимально простым для чтения человеком.
источник
Как я писал по аналогичному вопросу, правила оптимизации следующие:
1) Не оптимизируйте
2) (только для экспертов) Оптимизировать позже
Когда оптимизация преждевременна? Как правило.
Исключение может быть в вашем дизайне или в хорошо инкапсулированном коде, который активно используется. В прошлом я работал над некоторым критичным по времени кодом (реализацией RSA), где просмотр ассемблера, созданного компилятором, и удаление единственной ненужной инструкции во внутреннем цикле давали ускорение на 30%. Но ускорение от использования более сложных алгоритмов было на несколько порядков больше.
Еще один вопрос, который следует задать себе при оптимизации: «делаю ли я здесь эквивалент оптимизации для модема со скоростью 300 бод?» . Другими словами, закон Мура сделает вашу оптимизацию неуместной в ближайшее время. Многие проблемы масштабирования можно решить, просто добавив больше оборудования.
И последнее, но не менее важное: еще рано проводить оптимизацию, пока программа не будет работать слишком медленно. Если вы говорите о веб-приложении, вы можете запустить его под нагрузкой, чтобы увидеть узкие места, но есть вероятность, что у вас будут те же проблемы масштабирования, что и на большинстве других сайтов, и будут применяться те же решения.
edit: Между прочим, что касается связанной статьи, я бы поставил под сомнение многие сделанные предположения. Во-первых, неправда, что закон Мура перестал работать в 90-е годы. Во-вторых, не очевидно, что время пользователя более ценно, чем время программиста. Большинство пользователей (мягко говоря) в любом случае не лихорадочно используют каждый доступный цикл ЦП, они, вероятно, ждут, пока сеть что-то сделает. Плюс к этому есть альтернативные издержки, когда время программиста отвлекается от реализации чего-то другого, чтобы сэкономить несколько миллисекунд на том, что программа делает, пока пользователь разговаривает по телефону. Все, что длиннее, обычно не является оптимизацией, это исправление ошибок.
источник