Мы должны все еще оптимизировать “в маленьком”?

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

{
  #...
  "orientation":  "landscape"
}

и затем включите его в заголовок шаблона:


    
    


[116 ] Подробнее о манифесте веб-приложения можно узнать здесь

.

16
задан Mark Beckwith 20 April 2009 в 20:19
поделиться

22 ответа

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

17
ответ дан 30 November 2019 в 15:02
поделиться

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

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

inc eax

или

add eax, 1

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

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

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

0
ответ дан 30 November 2019 в 15:02
поделиться
  • I don't generally optimize lower than the O(f(n)) complexity unless I'm writing on an embedded device.

  • For typical g++/Visual Studio work, I presume that the basic optimizations are going to be reliably made(at least when optimization is requested). For less mature compilers, that assumption is presumably not valid.

  • If I was doing heavy maths work on streams of data, I'd check the compiler's ability to emit SIMD instructions.

  • I'd rather tune my code around different algorithms than a specific version of a specific compiler. Algorithms will stand the test of multiple processors/compilers, whereas if you tune for the 2008 Visual C++(first release) version, your optimizations may not even work next year.

  • Certain optimization tricks that are very reasonable in older computers prove to have issues today. E.g., the ++/++ operators were designed around an older architecture that had an increment instruction that was very fast. Today, if you do something like

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

    I would presume that the compiler would optimize i+=1 into an inc instruction(if the CPU had it).

  • The classic advice is to optimize top-down.

1
ответ дан 30 November 2019 в 15:02
поделиться

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

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

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

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

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

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

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

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

1
ответ дан 30 November 2019 в 15:02
поделиться

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

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

1
ответ дан 30 November 2019 в 15:02
поделиться

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

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

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

1
ответ дан 30 November 2019 в 15:02
поделиться

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

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

1
ответ дан 30 November 2019 в 15:02
поделиться

Я бы выбрал противоположный подход: забудь распаковать, придерживайся немного.

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

my $word = ($byte0 << 24) + ($byte1 << 16) + ($byte2 << 8) + $byte3;

Теперь извлеките части слова: бит знака, экспонента и мантисса:

my $sign = ($word & 0x80000000) ? -1 : 1;
my $expo = (($word & 0x7F800000) >> 23) - 127;
my $mant = ($word & 0x007FFFFF | 0x00800000);

Соберите ваш float:

my $num = $sign * (2 ** $expo) * ( $mant / (1 << 23));

Есть несколько примеров по Википедия .

  • Протестировал это на 0xC2ED4000 => -118.625, и это работает.
  • Протестировал это на 0x3E200000 => 0.15625 и обнаружил ошибку! (исправлено)
  • Не забывайте обрабатывать бесконечности и NaN, когда $ expo == 255
- 121 --- 2954490--

Также нужно быть осторожным, чтобы переходить от пре / постинкрементного увеличения Операторы / декремент не создают нежелательного побочного эффекта. Например, если вы повторяя цикл 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

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

#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

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

#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

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

2
ответ дан 30 November 2019 в 15:02
поделиться

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

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

2
ответ дан 30 November 2019 в 15:02
поделиться

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

2
ответ дан 30 November 2019 в 15:02
поделиться

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

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

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

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

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

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

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

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

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

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

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

2
ответ дан 30 November 2019 в 15:02
поделиться

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

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

2
ответ дан 30 November 2019 в 15:02
поделиться

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

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

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

2
ответ дан 30 November 2019 в 15:02
поделиться

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

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

3
ответ дан 30 November 2019 в 15:02
поделиться

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

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

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

x = y / 2;

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

6
ответ дан 30 November 2019 в 15:02
поделиться

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

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

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

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

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

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

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

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

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

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

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

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

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

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

7
ответ дан 30 November 2019 в 15:02
поделиться

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

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

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

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

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

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

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

7
ответ дан 30 November 2019 в 15:02
поделиться

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

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

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

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

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

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

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

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

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

10
ответ дан 30 November 2019 в 15:02
поделиться

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

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

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

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

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

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

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

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

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

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

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

Низкоуровневая оптимизация должна быть сделана, когда диагностика говорит, что у вас есть горячая точка (то есть некоторый код в нижней части стека вызовов появляется на достаточном количестве выборок стека вызовов (10% или более), что, как известно, стоит значительное время). И если горячая точка в коде, вы можете редактировать. Если у вас есть «горячая точка» в «новом», «удаленном» или строковом сравнении, ищите в стеке вещи, от которых нужно избавиться.

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

Низкоуровневая оптимизация должна быть сделана, когда диагностика говорит, что у вас есть горячая точка (то есть некоторый код в нижней части стека вызовов появляется на достаточном количестве выборок стека вызовов (10% или более), что, как известно, стоит значительного времени). И если горячая точка в коде, вы можете редактировать. Если у вас есть «горячая точка» в «новом», «удаленном» или строковом сравнении, ищите в стеке вещи, от которых нужно избавиться.

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

22
ответ дан 30 November 2019 в 15:02
поделиться

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

2
ответ дан 30 November 2019 в 15:02
поделиться

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

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

0
ответ дан 30 November 2019 в 15:02
поделиться