Мой коллега сегодня создал класс под названием ThreadLocalFormat
, который в основном переместил экземпляры классов Java Format в локальный поток, поскольку они не безопасны для потоков и «относительно дороги» в создании. Я написал быстрый тест и рассчитал, что смогу создать 200 000 экземпляров в секунду, спросил его, не создает ли он столько, на что он ответил «далеко не так много». Он отличный программист, и все в команде очень опытны, поэтому у нас нет проблем с пониманием получающегося кода, но это был случай оптимизации, когда в этом нет реальной необходимости. Он подтвердил код по моей просьбе. Как вы думаете? Это случай "преждевременной оптимизации" и насколько это плохо на самом деле?
design
optimization
architecture
Craig Day
источник
источник
Ответы:
Важно иметь в виду полную цитату:
Это означает, что при отсутствии проблем с измеряемой производительностью оптимизировать не следует, поскольку вы думаете, что получите выигрыш в производительности. Существуют очевидные оптимизации (например, не выполняется конкатенация строк в узком цикле), но следует избегать всего, что не является тривиально понятной оптимизацией, до тех пор, пока ее не измерить.
Самые большие проблемы с «преждевременной оптимизацией» состоят в том, что она может привести к неожиданным ошибкам и может быть огромной тратой времени.
источник
HashSet
вместоList
оптимизации было преждевременным. Рассматриваемый вариант использования представлял собой статически инициализированную коллекцию, единственная цель которой состояла в том, чтобы служить справочной таблицей. Я не думаю, что я ошибаюсь, говоря, что есть различие в выборе правильного инструмента для работы и преждевременной оптимизации. Я думаю, что ваш пост подтверждает эту философию:There are obvious optimizations...anything that isn't trivially clear optimization should be avoided until it can be measured.
оптимизация HashSet была тщательно измерена и задокументирована.Set
также более семантически корректен и информативенList
, так что здесь есть не только аспект оптимизации.Преждевременные микро оптимизации корень всех зол, потому что микро оптимизации оставить вне контекста. Они почти никогда не ведут себя так, как они ожидают.
Каковы некоторые хорошие ранние оптимизации в порядке важности:
Некоторые оптимизации середины цикла разработки:
Некоторые оптимизации в конце цикла разработки
Не все ранние оптимизации являются злыми, микрооптимизации являются злыми, если они выполняются в неподходящее время в жизненном цикле разработки , поскольку они могут отрицательно влиять на архитектуру, могут отрицательно влиять на начальную производительность, могут быть неуместны в отношении производительности или даже оказывать отрицательное влияние в конце развития из-за различных условий окружающей среды.
Если производительность вызывает беспокойство (и всегда должно быть), всегда мыслить масштабно . Производительность - это большая картина, а не такие вещи, как: использовать ли int или long ? Перейти к списку вниз при работе с производительностью , а не снизу вверх .
источник
оптимизация без первого измерения почти всегда преждевременна.
Я считаю, что это верно в этом случае, и верно в общем случае.
источник
Оптимизация является «злом», если она вызывает:
В вашем случае кажется, что немного времени программиста уже потрачено, код не был слишком сложным (из вашего комментария можно было догадаться, что все в команде смогут понять), и код немного более надежен в будущем (будучи теперь безопасно, если я понял ваше описание). Похоже, только немного зла. :)
источник
Я удивлен, что этому вопросу 5 лет, и все же никто не опубликовал больше того, что должен был сказать Кнут, чем пару предложений. Пара абзацев, окружающих известную цитату, объясняют это довольно хорошо. Цитируемый документ называется « Структурированное программирование с переходом к утверждениям », и, хотя ему уже почти 40 лет, он посвящен спорам и программному движению, которого больше нет, и есть примеры на языках программирования, которых многие люди никогда не видели слышал о, удивительно большое количество того, что он сказал, все еще применяется.
Вот большая цитата (со страницы 8 в pdf, страница 268 в оригинале):
Еще один хороший момент с предыдущей страницы:
источник
Я часто видел, как эта цитата использовалась для обоснования явно плохого кода или кода, который, хотя его производительность не была измерена, возможно, можно было бы сделать довольно быстро, без увеличения размера кода или снижения его читабельности.
В целом, я думаю, что ранняя микрооптимизация может быть плохой идеей. Однако макрооптимизация (например, выбор алгоритма O (log N) вместо O (N ^ 2)) часто имеет смысл и должна быть сделана рано, поскольку написание алгоритма O (N ^ 2) и затем выбросить его полностью в пользу подхода O (log N).
Обратите внимание, что слова могут быть следующими : если алгоритм O (N ^ 2) прост и легко написать, вы можете выбросить его позже без особой вины, если он окажется слишком медленным. Но если оба алгоритма одинаково сложны или ожидаемая рабочая нагрузка настолько велика, что вы уже знаете, что вам понадобится более быстрый, то ранняя оптимизация - это разумное инженерное решение, которое в долгосрочной перспективе уменьшит вашу общую рабочую нагрузку.
Таким образом, в целом, я думаю, что правильный подход состоит в том, чтобы выяснить, какие у вас есть варианты, прежде чем вы начнете писать код, и сознательно выбрать лучший алгоритм для вашей ситуации. Самое главное, что фраза «преждевременная оптимизация - корень всего зла» не оправдывает невежество. Карьерный разработчик должен иметь общее представление о том, сколько стоят общие операции; они должны знать, например,
И разработчики должны быть знакомы с набором инструментов структур данных и алгоритмов, чтобы они могли легко использовать правильные инструменты для работы.
Обладая достаточными знаниями и личным инструментарием, вы можете оптимизировать работу практически без усилий. Вкладывать много усилий в оптимизацию, которая может оказаться ненужной, - зло (и я признаю, что попадал в эту ловушку не раз). Но если оптимизация так же проста, как выбор набора / хеш-таблицы вместо массива или сохранение списка чисел в double [] вместо string [], то почему бы и нет? Возможно, я не согласен с Кнутом здесь, я не уверен, но я думаю, что он говорил об оптимизации низкого уровня, тогда как я говорю об оптимизации высокого уровня.
Помните, что эта цитата была написана в 1974 году. В 1974 году компьютеры работали медленно, а вычислительная мощность была дорогой, что давало некоторым разработчикам тенденцию к чрезмерной оптимизации, построчно. Я думаю, что это то, против чего Кнут добивался. Он не говорил «вообще не беспокойся о производительности», потому что в 1974 году это было бы просто сумасшествием. Кнут объяснял, как оптимизировать; Короче говоря, следует сосредоточиться только на узких местах, и, прежде чем сделать это, вы должны выполнить измерения, чтобы найти узкие места.
Обратите внимание, что вы не можете найти узкие места, пока не напишете программу для измерения, а это означает, что некоторые решения о производительности должны быть приняты до того, как что-либо измерить. Иногда эти решения трудно изменить, если вы ошибаетесь. По этой причине хорошо иметь общее представление о том, что стоит, чтобы вы могли принимать разумные решения, когда нет надежных данных.
Как рано оптимизировать, и сколько беспокоиться о производительности, зависит от работы. При написании сценариев, которые вы запускаете всего несколько раз, беспокойство по поводу производительности обычно является пустой тратой времени. Но если вы работаете на Microsoft или Oracle и работаете над библиотекой, которую тысячи других разработчиков будут использовать тысячами различных способов, это может оказаться полезным для оптимизации, так что вы сможете охватить все разнообразные эффективно использовать варианты. Тем не менее, потребность в производительности всегда должна быть сбалансирована с потребностью в удобочитаемости, удобстве обслуживания, элегантности, расширяемости и так далее.
источник
Лично, как было сказано в предыдущем потоке , я не считаю, что ранняя оптимизация плоха в ситуациях, когда вы знаете, что столкнетесь с проблемами производительности. Например, я пишу программное обеспечение для моделирования и анализа поверхностей, где я регулярно работаю с десятками миллионов объектов. Планирование оптимальной производительности на этапе проектирования намного превосходит позднюю оптимизацию слабого проекта.
Еще одна вещь, которую стоит рассмотреть, - как ваше приложение будет масштабироваться в будущем. Если вы считаете, что ваш код будет работать долго, оптимизация производительности на этапе проектирования также является хорошей идеей.
По моему опыту, поздняя оптимизация обеспечивает скудные вознаграждения по высокой цене. Оптимизация на этапе проектирования, путем выбора алгоритма и настройки, намного лучше. В зависимости от того, как профилировщик понимает, как работает ваш код, не является хорошим способом получения высокопроизводительного кода, вы должны знать об этом заранее.
источник
На самом деле я узнал, что преждевременная неоптимизация чаще всего является корнем всего зла.
Когда люди пишут программное обеспечение, у него изначально возникают проблемы, такие как нестабильность, ограниченные возможности, плохое использование и плохая производительность. Все это обычно исправляется, когда программное обеспечение становится зрелым.
Все это, кроме производительности. Кажется, никто не заботится о производительности. Причина проста: если происходит сбой программного обеспечения, кто-то исправит ошибку, и все, если какая-то функция отсутствует, кто-то ее реализует и сделает, если программное обеспечение имеет плохую производительность, это во многих случаях не из-за отсутствия микрооптимизации, а из-за плохого дизайна и никто не собирается трогать дизайн программного обеспечения. КОГДА-ЛИБО.
Посмотри на Бохса. Это медленно, как ад. Будет ли это когда-нибудь быстрее? Может быть, но только в пределах нескольких процентов. Он никогда не достигнет производительности, сравнимой с программным обеспечением для виртуализации, таким как VMWare, VBox или даже QEMU. Потому что это медленно по дизайну!
Если проблема программного обеспечения в том, что оно медленное, то потому, что оно ОЧЕНЬ медленное, и это можно исправить только путем улучшения производительности множеством. + 10% просто не сделают медленное программное обеспечение быстрым. И вы, как правило, не получите более 10% от последующих оптимизаций.
Поэтому, если производительность ЛЮБОГО важна для вашего программного обеспечения, вы должны принимать это во внимание с самого начала, при проектировании, вместо того, чтобы думать: «О, да, это медленно, но мы можем улучшить это позже». Потому что ты не можешь!
Я знаю, что это не совсем соответствует вашему конкретному случаю, но отвечает на общий вопрос: «Действительно ли преждевременная оптимизация - корень всего зла?» - с явным НЕТ.
Каждая оптимизация, как любая функция и т. Д., Должна быть тщательно разработана и тщательно реализована. И это включает в себя правильную оценку затрат и выгод. Не оптимизируйте алгоритм, чтобы сэкономить несколько циклов здесь и там, когда он не создает ощутимого прироста производительности.
Просто в качестве примера: вы можете улучшить производительность функции, вставив ее, возможно, сэкономив несколько циклов, но в то же время вы, вероятно, увеличите размер исполняемого файла, увеличивая шансы TLB и промахов кэша, стоящих тысячи циклов или даже операции подкачки, которые полностью убивают производительность. Если вы не понимаете этих вещей, ваша «оптимизация» может оказаться плохой.
Глупая оптимизация является более злой, чем «преждевременная» оптимизация, но обе они все же лучше, чем преждевременная неоптимизация
источник
С ПО есть две проблемы: во-первых, время разработки используется для несущественной работы, которую можно использовать для написания большего количества функций или исправления большего количества ошибок, и во-вторых, ложное чувство безопасности, что код работает эффективно. PO часто включает в себя оптимизацию кода, который не будет узким местом, при этом не замечая код, который будет. Бит «преждевременный» означает, что оптимизация выполняется до того, как проблема идентифицируется с использованием надлежащих измерений.
Так что, в принципе, да, это звучит как преждевременная оптимизация, но я бы не стал ее опровергать, если бы в ней не было ошибок - в конце концов, теперь она оптимизирована (!)
источник
Я полагаю, что это то, что Майк Кон называет «позолотой» кода - т. Е. Тратить время на вещи, которые могут быть хорошими, но не обязательными.
Он посоветовал против этого.
PS «Позолота» может быть специфической функциональностью. Когда вы смотрите на код, он принимает форму ненужной оптимизации, «ориентированных на будущее» классов и т. Д.
источник
Поскольку нет проблем с пониманием кода, этот случай можно рассматривать как исключение.
Но в целом оптимизация приводит к менее читаемому и менее понятному коду и должна применяться только при необходимости. Простой пример - если вы знаете, что вам нужно отсортировать только пару элементов - используйте BubbleSort. Но если вы подозреваете, что количество элементов может увеличиться, а вы не знаете, сколько, оптимизация с помощью QuickSort (например) - это не зло, а необходимость. И это следует учитывать при разработке программы.
источник
Я обнаружил, что проблема с преждевременной оптимизацией чаще всего возникает, когда переписывание существующего кода происходит быстрее. Во-первых, я понимаю, как может возникнуть проблема, если написать какую-то запутанную оптимизацию, но в основном я вижу, что преждевременная оптимизация поднимает свою уродливую голову в исправлении того, что не сломалось (как известно).
И худший пример этого - всякий раз, когда я вижу, как кто-то повторно реализует функции из стандартной библиотеки. Это главный красный флаг. Например, я однажды видел, как кто-то реализовывал пользовательские процедуры для работы со строками, потому что он был обеспокоен тем, что встроенные команды были слишком медленными.
Это приводит к тому, что код становится труднее понять (плохо) и тратит много времени на работу, что, вероятно, бесполезно (плохо).
источник
С другой точки зрения, по моему опыту, большинство программистов / разработчиков не планируют успеха, и «прототип» почти всегда становится Release 1.0. Я имею непосредственный опыт работы с 4 отдельными оригинальными продуктами, в которых стильный, сексуальный и высоко функциональный интерфейс (в основном пользовательский интерфейс) привел к широкому распространению пользовательского признания и энтузиазма. В каждом из этих продуктов проблемы производительности начали появляться в течение относительно коротких промежутков времени (от 1 до 2 лет), особенно когда более крупные и требовательные клиенты начали внедрять этот продукт. Очень скоро производительность доминировала в списке проблем, хотя разработка новых функций доминировала в списке приоритетов менеджмента. Клиенты становились все более и более разочарованными, поскольку в каждом выпуске добавлялись новые функции, которые звучали великолепно, но были почти недоступны из-за проблем с производительностью.
Таким образом, очень фундаментальные недостатки дизайна и реализации, которые не имели большого значения или не имели никакого отношения к «прототипу», стали основным камнем преткновения для долгосрочного успеха продуктов (и компаний).
Демонстрация вашего клиента может отлично выглядеть и работать на вашем ноутбуке с XML DOM, SQL Express и большим количеством кэшированных данных на стороне клиента. Производственная система, вероятно, вылетит, если вы добьетесь успеха.
В 1976 году мы все еще обсуждали оптимальные способы вычисления квадратного корня или сортировки большого массива, и пословица Дона Кнута была направлена на ошибку, состоящую в том, чтобы сосредоточиться на оптимизации такого рода низкоуровневой рутины в начале процесса проектирования, а не на решении проблемы. а затем оптимизировать локализованные области кода.
Когда кто-то повторяет эту пословицу в качестве оправдания за то, что он не пишет эффективный код (C ++, VB, T-SQL или иным образом), или за неправильное проектирование хранилища данных, или за то, что он не рассматривает архитектуру сетевой работы, тогда IMO просто демонстрируют очень поверхностное понимание реального характера нашей работы. луч
источник
Я полагаю, это зависит от того, как вы определяете «преждевременный». Создание низкоуровневой функциональности быстро, когда вы пишете, не является по своей сути злом. Я думаю, что это неправильное понимание цитаты. Иногда я думаю, что эта цитата могла бы сделать с некоторыми уточнениями. Я бы повторил комментарии m_pGladiator о читабельности.
источник
Ответ: это зависит. Я буду утверждать, что эффективность имеет большое значение для определенных видов работ, таких как сложные запросы к базе данных. Во многих других случаях компьютер тратит большую часть своего времени на ожидание пользовательского ввода, поэтому оптимизация большей части кода в лучшем случае является пустой тратой усилий, а в худшем - контрпродуктивной.
В некоторых случаях вы можете проектировать для эффективности или производительности (воспринимаемой или реальной) - выбирая подходящий алгоритм или проектируя пользовательский интерфейс, чтобы, например, в фоновом режиме выполнялись определенные дорогостоящие операции. Во многих случаях профилирование или другие операции для определения горячих точек дают вам преимущество 10/90.
Примером, который я могу описать, является модель данных, которую я однажды сделал для системы управления делами в суде, в которой было около 560 таблиц. Сначала все нормализовалось («красиво нормализовано», как выразился консультант из одной крупной пятерки), и нам нужно было поместить в него только четыре элемента денормализованных данных:
Один материализованный вид для поддержки экрана поиска
Одна таблица с поддержкой триггера для поддержки другого экрана поиска, который не может быть выполнен с материализованным представлением.
Одна денормализованная таблица отчетов (она существовала только потому, что нам приходилось брать некоторые отчеты о пропускной способности, когда проект хранилища данных был закрыт)
Одна поддерживаемая триггером таблица для интерфейса, который должен был искать самое последнее из довольно большого числа разнородных событий в системе.
Это был (в то время) крупнейший проект J2EE в Австралии - более 100 лет времени разработки - и в схеме базы данных было 4 денормализованных элемента, один из которых на самом деле не принадлежал вообще.
источник
Преждевременная оптимизация не является корнем ВСЕГО зла, это точно. Есть, однако, недостатки этого:
Вместо преждевременной оптимизации можно было бы провести ранние тесты видимости, чтобы увидеть, есть ли реальная потребность в лучшей оптимизации.
источник
Большинство из тех, кто придерживается «PMO» (то есть частичной цитаты), говорят, что оптимизации должны основываться на измерениях, и измерения не могут быть выполнены до самого конца.
Мой опыт разработки крупных систем также показывает, что тестирование производительности выполняется в самом конце, так как разработка близится к завершению.
Если бы мы следовали «советам» этих людей, все системы были бы мучительно медленными. Они также будут дорогими, потому что их аппаратные потребности намного больше, чем предполагалось изначально.
Я давно выступал за проведение тестов производительности через регулярные промежутки времени в процессе разработки: это будет указывать как на наличие нового кода (там, где раньше его не было), так и на состояние существующего кода.
Другая любимая идея состоит в том, чтобы установить программное обеспечение на уровне функциональных блоков. По мере выполнения система собирает информацию о времени выполнения для функциональных блоков. Когда обновление системы выполнено, можно определить, какие функциональные блоки выполняют так же, как в предыдущем выпуске, и те, которые вышли из строя. На экране программного обеспечения данные о производительности могут быть доступны из меню справки.
Посмотрите на эту превосходную статью о том, что PMO может или не может означать.
источник