Должны ли мы все еще оптимизировать "в малом"?

Я менял цикл для увеличения ++i вместо i++ и задумался, это действительно необходимо больше? Конечно, современные компиляторы делают эту оптимизацию самостоятельно.

В этой статье, http://leto.net/docs/C-optimization.php, с 1997 года Майкл Ли занимается другими оптимизациями, такими как встраивание, разворачивание петли, заклинивание петли, инверсия петли, снижение прочности и многие другие. Они все еще актуальны?

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

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

анекдот: однажды я просмотрел спецификацию требований, в которой говорилось: "Программист должен сдвинуть смещение на единицу вместо умножения на 2".

22 ответа

Решение

Если для оптимизации нет затрат, сделайте это. При написании кода, ++i так же легко написать, как i++, поэтому предпочитаю первое. Там нет стоимости для этого.

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

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

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

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

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

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

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

Таким образом, такие "мелкомасштабные" оптимизации все еще могут быть необходимы, если 1) вам действительно нужна производительность, и 2) у вас есть информация, которой нет у компилятора.

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

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

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

Существуют кривые компромисса между производительностью и другими вещами, такими как память и ясность, верно? И вы ожидаете, что для повышения производительности вам придется что-то бросить, верно?

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

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

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

Так что я занимаюсь одной проблемой за раз. Я называю эти "слизняки", сокращенно "ошибки медлительности". Каждый удаляемый слизень дает ускорение от 1,1х до 10х, в зависимости от того, насколько он плох. Каждый удаляемый слаг заставляет оставшихся брать большую долю оставшегося времени, поэтому их легче найти. Таким образом, все "низко висящие фрукты" можно быстро утилизировать.

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

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

ДОБАВЛЕНО: Теперь, чтобы попытаться ответить на ваш вопрос, необходимо выполнить низкоуровневую оптимизацию, когда диагностика говорит, что у вас есть горячая точка (т.е. некоторый код в нижней части стека вызовов появляется на достаточном количестве образцов стека вызовов (10% или более) должно быть известно, что стоит значительного времени). И если горячая точка в коде вы можете редактировать. Если у вас есть горячая точка в "новом", "удаленном" или строковом сравнении, посмотрите выше в стеке, чтобы избавиться от вещей.

Надеюсь, это поможет.

Эти оптимизации все еще актуальны. Что касается вашего примера, использование ++ i или i ++ для встроенного арифметического типа не имеет никакого эффекта.

В случае определяемых пользователем операторов увеличения / уменьшения ++ i предпочтительнее, поскольку это не подразумевает копирование увеличенного объекта.

Поэтому хорошим стилем кодирования является использование префикса приращения / уменьшения в циклах for.

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

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

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

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

Если вы измерили и определили, что определенная функция или цикл является горячей точкой, существует два подхода для ее оптимизации:

  • Во-первых, оптимизируйте его на более высоком уровне, уменьшив количество вызовов дорогостоящего кода. Это обычно приводит к большей выгоде. Улучшения уровня алгоритма попадают в этот уровень - алгоритм будет лучше, если big-O приведет к меньшему количеству выполнения кода горячей точки.
  • Если количество звонков не может быть уменьшено, вам следует подумать о микрооптимизации. Посмотрите на фактический машинный код, который генерирует компилятор, и определите, что он делает, что является наиболее дорогостоящим - если выясняется, что происходит копирование временных объектов, то рассмотрите префикс ++ вместо постфикса. Если это делает ненужное сравнение в начале цикла, переверните цикл в do/while и так далее. Не понимая, почему код работает медленно, любые общие микрооптимизации практически бесполезны.

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

Если вас не волнует переносимость, и вы довольно заняты математикой, то вы можете также использовать любые доступные на вашей целевой платформе векторные операции - SSE на x86, Altivec на PPC. Компиляторы не могут легко использовать эти инструкции без большой помощи, а встроенные функции довольно просты в использовании в наши дни. Еще одна вещь, которая не упоминается в документе, на который вы ссылаетесь, это наложение указателя. Иногда вы можете получить хорошие улучшения скорости, если ваш компилятор поддерживает какое-то ключевое слово restrict. Плюс, конечно, важно думать об использовании кэша. Реорганизация кода и данных таким образом, чтобы эффективно использовать кэш, может привести к значительному увеличению скорости по сравнению с оптимизацией удаления нечетной копии или развертыванием цикла.

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

Плохой пример - решение, использовать ли ++i или же i++ не предполагает какого-либо компромисса! ++i имеет (может иметь) чистую выгоду без каких-либо минусов. Есть много подобных сценариев, и любое обсуждение в этих сферах - пустая трата времени.

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

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

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

Все оптимизации, которые вы перечислили, в наши дни практически не имеют значения для программистов на Си - компилятор намного, намного лучше выполняет такие вещи, как встраивание, развертывание цикла, заклинивание цикла, инверсия цикла и снижение прочности.

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

Что касается использования сдвигов вместо умножения на степени 2, опять же, компилятор уже сделает это за вас. В зависимости от архитектуры, он может делать еще более умные вещи, такие как превращение умножения на 5 в одно lea инструкция по x86. Однако, с делениями и модулями по степеням 2, вам, возможно, придется уделить немного больше внимания, чтобы получить оптимальный код. Предположим, вы пишете:

x = y / 2;

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

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

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

Идите зеленый, спасите планету, оптимизируйте себя

Есть три цитаты, которые я считаю, что каждый разработчик должен знать об оптимизации - я сначала прочитал их в книге Джоша Блоха "Эффективная Java":

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

( Уильям А. Вульф)

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

( Дональд Э. Кнут)

Мы придерживаемся двух правил в отношении оптимизации:

Правило 1: не делай этого.

Правило 2: (только для экспертов). Пока не делайте этого - то есть, пока у вас нет совершенно ясного и неоптимизированного решения.

( М. А. Джексон)

Все эти цитаты (AFAIK), по крайней мере, 20-30 лет, время, когда процессор и память значат гораздо больше, чем сегодня. Я считаю, что правильный способ разработки программного обеспечения - это сначала иметь работающее решение, а затем использовать профилировщик для проверки узких мест производительности. Однажды мой друг рассказал мне о приложении, которое было написано на C++ и Delphi и имело проблемы с производительностью. Используя профилировщик, они обнаружили, что приложение потратило значительное количество времени на преобразование строк из структуры Delphi в структуру C++ и наоборот - никакая микрооптимизация не может обнаружить это...

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

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

#include <iostream>

int main()
{
  for (unsigned int i = 5; i != 0; i--)
    std::cout << i << std::endl;

  for (unsigned int i = 5; i != 0; --i)
    std::cout << "\t" << i << std::endl;

  for (unsigned int i = 5; i-- != 0; )
    std::cout << i << std::endl;

  for (unsigned int i = 5; --i != 0; )
    std::cout << "\t" << i << std::endl;
}

результаты в следующем:

5
4
3
2
1
        5
        4
        3
        2
        1
4
3
2
1
0
        4
        3
        2
        1

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

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

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

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

В прошлый раз, когда я тестировал ++it и it++ на компиляторе Microsoft C++ для итераторов STL, ++ выдавал меньше кода, поэтому, если вы находитесь в большом цикле, вы можете получить небольшой выигрыш в производительности, используя ++it.

Для целых чисел и т. Д. Компилятор выдаст идентичный код.

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

Сделайте это правильно, а затем сделайте это быстро - на основе измерения производительности.

Хорошо выбирайте алгоритмы и реализуйте их НАИБОЛЕЕ ЧИТАЕМЫМ способом. Поменяйте читабельность на производительность только тогда, когда вы ДОЛЖНЫ - то есть когда ваш пользователь скажет, что производительность недопустима ни словами, ни своими действиями.

Как сказал Дональд Кнут / Тони Хоар, "преждевременная оптимизация - корень всего зла" - все еще верно и сейчас, 30 лет спустя...

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

Тем не менее, в контексте вашего вопроса о том, может ли компилятор выполнить эти оптимизации для вас, в выбранном вами примере это невозможно. Причина в том, что ++ i и i ++ имеют разные значения, поэтому они реализованы как разные функции. i ++ должен проделать дополнительную работу (чтобы скопировать текущее состояние перед приращением, сделать приращение, а затем вернуть это состояние). Если вам не нужна эта дополнительная работа, то зачем выбирать эту форму, другую, более прямую? Ответ может быть читабельностью - но в C++ в этом случае стало писать идиоматически, поэтому я не верю, что читаемость приходит в это.

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

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

"Программист должен сдвинуть сдвиг на единицу вместо умножения на 2". надеюсь, вы не хотите умножать числа с плавающей запятой или отрицательные числа;)

  • Я обычно не оптимизирую ниже, чем сложность O(f(n)), если я не пишу на встроенном устройстве.

  • Для типичной работы с g++/Visual Studio я предполагаю, что основные оптимизации будут выполнены надежно (по крайней мере, когда будет запрошена оптимизация). Для менее зрелых компиляторов это предположение предположительно неверно.

  • Если бы я выполнял тяжелую математическую работу с потоками данных, я бы проверил способность компилятора выдавать SIMD-инструкции.

  • Я бы лучше настроил свой код на разные алгоритмы, чем на конкретную версию конкретного компилятора. Алгоритмы выдержат испытание нескольких процессоров / компиляторов, в то время как если вы настроитесь на версию 2008 Visual C++(первый выпуск), ваши оптимизации могут даже не сработать в следующем году.

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

    for(int i = 0; i < top; i+=1)

    Я бы предположил, что компилятор будет оптимизировать i+=1 в inc инструкция (если процессор был у него).

  • Классический совет - оптимизировать сверху вниз.

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

Что-то вроде ++i, компромисс между временем и удобочитаемостью настолько мал, что, возможно, стоит привыкнуть, если это действительно приведет к улучшению.

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

  1. производится функциональный код
  2. профилировать этот код
  3. выявленные узкие места
  4. упрощенная конструкция для устранения узких мест
  5. выбранные алгоритмы, минимизирующие вызовы в узкие места

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

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

Прежде всего - всегда запускайте профилирование для проверки.

Во-первых, если вы оптимизируете правильную часть кода. Если код выполняется на 1% от общего времени - забудьте. Даже если вы уменьшите его на 50%, вы получите ускорение всего на 0,5%. Если вы не делаете что-то странное, ускорение будет намного медленнее (особенно если вы использовали хороший оптимизирующий компилятор). Во-вторых, если вы оптимизируете это правильно. Какой код будет работать быстрее на x86?

inc eax

или же

add eax, 1

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

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

В общем - делайте это только если вы должны и / или знаете, что делаете. Это потребует некоторого количества знаний о коде, компиляторе и низкоуровневой компьютерной архитектуре, которые не упомянуты в этом вопросе (и, честно говоря, я не обладаю ими). И это, вероятно, ничего не выиграет. Если вы хотите оптимизировать - делайте это на более высоком уровне.

Я все еще делаю такие вещи, как ra<<=1; вместо ra*=2; И продолжим. Но компиляторы (какими бы плохими они ни были) и, что более важно, скорость компьютеров настолько высоки, что эти оптимизации часто теряются в шуме. Как правило, нет, это того не стоит, если вы находитесь на платформе с ограниченными ресурсами (скажем, на микроконтроллере), где каждый лишний такт действительно имеет значение, тогда вы, вероятно, уже делаете это и, вероятно, делаете немало настроек ассемблера. По привычке я стараюсь не давать компилятору слишком много дополнительной работы, но из-за читаемости и надежности кода я не отказываюсь от своих усилий.

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

Другие вопросы по тегам