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

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

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

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

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

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

Ответы [ 20 ]

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

При программировании необходим ряд параметров. Среди них:

  • читаемость
  • ремонтопригодность
  • Сложность
  • Надёжность
  • Корректность
  • Производительность
  • Время разработки

Оптимизация (исходя из производительности) часто происходит за счет других параметров и должна быть сбалансирована с "потерями" в этих областях.

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

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

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

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

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

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

2 голосов
/ 22 декабря 2017

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

[...] опять же, это заметная экономия в общей скорости бега, если, скажем, среднее значение n составляет около 20, и если процедура поиска выполняется около миллиона раз в программе. Такой круг оптимизации [с использованием gotos] не сложны для изучения и, как я имею сказали, что они уместны лишь в небольшой части программы, но они часто приносят существенную экономию. [...]

И продолжает:

Общепринятая мудрость, разделяемая многими современными программистами призывает игнорировать эффективность в малом; но я верю, что это просто чрезмерная реакция на злоупотребления, которые они видят, практикуемые глупые программисты, которые не могут отлаживать или поддерживать их "оптимизированные" программы. В установленных инженерных дисциплинах 12% улучшение, легко достижимое, никогда не считается незначительным; и я полагаю, что та же точка зрения должна преобладать в разработке программного обеспечения. из Конечно, я бы не стал делать такие оптимизации на одноразовой работе, но когда речь идет о подготовке качественных программ, я не хочу ограничиться инструментами, которые лишают меня такой эффективности [то есть goto заявления в этом контексте].

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

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

... а затем еще немного о важности инструментов профилирования:

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

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

Тем не менее, это была цитата в пользу соответственно примененных микрооптимизаций при использовании опытной рукой, держащей профилировщик. Сегодняшний аналогичный эквивалент может выглядеть так: «Люди не должны делать слепые удары при оптимизации своего программного обеспечения, но пользовательские распределители памяти могут иметь огромное значение при применении в ключевых областях для улучшения локальности ссылок», или, « Рукописный SIMD-код с использованием представителя SoA действительно трудно поддерживать, и его не следует использовать повсеместно, но он может потреблять память намного быстрее, если его применяет опытная и управляемая рука. »

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

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

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

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

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

Я думаю, что «преждевременная оптимизация» невероятно субъективна.

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

Редизайн с самого начала обходится дороже, чем оптимизация дизайна очевидными способами.

Очевидно, что некоторые мелочи будут пропущены в первый раз, но это редко являются ключевыми проектными решениями.

Следовательно: НЕ оптимизировать дизайн - это IMO - запах кода сам по себе.

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

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

Например, чтобы добавить в список Нормана:

  • Использование конкатенации StringBuilder в Java (или C # и т. Д.) Вместо String + String (в цикле);
  • Избегание зацикливания в C, например: for (i = 0; i < strlen(str); i++) (потому что здесь strlen - это вызов функции, перебирающий строку каждый раз, вызываемый в каждом цикле);
  • Кажется, что в большинстве реализаций JavaScript это тоже быстрее сделать for (i = 0 l = str.length; i < l; i++) и все еще читаемо, так что ОК.

И так далее. Но такая микрооптимизация никогда не должна идти за счет читабельности кода.

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

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

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

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

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

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

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

Как я уже писал по схожему вопросу, правила оптимизации:

1) Не оптимизировать

2) (только для экспертов) Оптимизировать позже

Когда оптимизация преждевременна? Обычно.

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

Другой вопрос, который нужно задать себе при оптимизации: «Я делаю здесь эквивалент оптимизации для модема на 300 бод?» . Другими словами, закон Мура сделает вашу оптимизацию неактуальной в ближайшее время. Многие проблемы масштабирования можно решить, просто добавив к ней больше оборудования.

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

edit: Кстати, в отношении связанной статьи я бы поставил под сомнение многие из сделанных предположений. Во-первых, это не правда, что закон Мура перестал работать в 90-х годах. Во-вторых, не очевидно, что время пользователя более ценно, чем время программиста. Большинство пользователей (мягко говоря) не отчаянно используют каждый доступный цикл ЦП, они, вероятно, ожидают, что сеть что-то предпримет. Плюс к этому есть альтернативные издержки, когда время программиста отвлекается от реализации чего-то другого, чтобы сэкономить несколько миллисекунд на том, что делает программа, пока пользователь разговаривает по телефону. Все, что длиннее, обычно не является оптимизацией, это исправление ошибок.

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

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

...