Каковы некоторые хорошие методы оптимизации кода?

У меня была та же проблема с моим списком ajax, я мог решить ее, позвонив по номеру reloadItems & amp; layouts функции после ответа ajax:

var mediaItemContainer = $( '#container' );
mediaItemContainer.masonry( {
    columnWidth:  '210px',
    itemSelector: '.item'
} );
$( mediaItemContainer ).prepend( '<div class="item">foo</div>' );
$( mediaItemContainer ).masonry( 'reloadItems' );
$( mediaItemContainer ).masonry( 'layout' );
5
задан esac 21 May 2009 в 22:28
поделиться

19 ответов

  1. Не думайте о производительности, думайте о ясности и правильности.
  2. Используйте профилировщик.
  3. Продолжайте использовать профилировщик.
  4. См. 1.
27
ответ дан 18 December 2019 в 05:11
поделиться

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

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

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

0
ответ дан 18 December 2019 в 05:11
поделиться

Профиль, профиль, профиль. По возможности используйте valgrind (вместе с визуализатором kcachegrind ), в противном случае используйте почтенный gprof .

Мои максимальные показатели производительности:

  1. Выделение памяти не освобождая его. Возможно только при использовании C и C ++.
  2. Выделение памяти.
  3. Вызов действительно небольших процедур, функций или методов, которые ваш компилятор каким-то образом не может встроить.
  4. Трафик памяти.

Все остальное - в шуме.

1
ответ дан 18 December 2019 в 05:11
поделиться
  • Оптимизируйте только тогда, когда у вас есть проблемы с производительностью.
  • Оптимизируйте только медленные части, как измерено!
  • Поиск лучшего алгоритма может сэкономить вам порядки, а не несколько процентов.

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

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

0
ответ дан 18 December 2019 в 05:11
поделиться

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

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

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

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

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

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

Итак, что я рекомендую вам сделать, это: Получите опыт. Это лучший учитель.

2
ответ дан 18 December 2019 в 05:11
поделиться

Правило номер один, которое я использую, - СУХОЙ (Не повторяйся). Я считаю, что это правило хорошо выделяет проблемные области, которые можно исправить, не нанося ущерба ясности программы. Это также упрощает устранение узких мест после их обнаружения.

4
ответ дан 18 December 2019 в 05:11
поделиться

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

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


Извините за напыщенную речь, а теперь перейдем к вашему актуальному вопросу:

Знайте свою среду! детали низкого уровня - например, доступ к памяти с нелинейностью, то, что компилятор может оптимизировать, и т. д. Уловка состоит в том, чтобы не беспокоиться о многом, о чем вам не следует » Я слишком сильно переживаю, просто имейте в виду.

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

Подумайте об алгоритмах, прежде чем думать о деталях реализации.
Большинство низкоуровневых оптимизаций дает вам фактор 1.1, другой алгоритм может дать вам коэффициент 10. Хорошая (!) Стратегия кэширования может дать вам коэффициент 100. Выяснив, что вам действительно не нужно делать вызов, вы получите Warp 10.

Это обычно заставляет меня задуматься о том, как организовать данные: какие частые операции являются потенциальными узкими местами или проблемами масштабируемости?

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

Подумайте об алгоритмах, прежде чем думать о деталях реализации.
Большинство низкоуровневых оптимизаций дает вам фактор 1.1, другой алгоритм может дать вам коэффициент 10. Хорошая (!) Стратегия кэширования может дать вам коэффициент 100. Выяснив, что вам действительно не нужно делать вызов, вы получите Warp 10.

Это обычно заставляет меня задуматься о том, как организовать данные: какие частые операции являются потенциальными узкими местами или проблемами масштабируемости?

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

Подумайте об алгоритмах, прежде чем думать о деталях реализации.
Большинство низкоуровневых оптимизаций дает вам фактор 1.1, другой алгоритм может дать вам коэффициент 10. Хорошая (!) Стратегия кэширования может дать вам коэффициент 100. Выяснив, что вам действительно не нужно делать вызов, вы получите Warp 10.

Это обычно заставляет меня задуматься о том, как организовать данные: какие частые операции являются потенциальными узкими местами или проблемами масштабируемости?

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

Подумайте об алгоритмах, прежде чем думать о деталях реализации.
Большинство низкоуровневых оптимизаций дает вам фактор 1.1, другой алгоритм может дать вам коэффициент 10. Хорошая (!) Стратегия кэширования может дать вам коэффициент 100. Выяснив, что вам действительно не нужно делать вызов, вы получите Warp 10.

Это обычно заставляет меня задуматься о том, как организовать данные: какие частые операции являются потенциальными узкими местами или проблемами масштабируемости?

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

Подумайте об алгоритмах, прежде чем думать о деталях реализации.
Большинство низкоуровневых оптимизаций дает вам фактор 1.1, другой алгоритм может дать вам коэффициент 10. Хорошая (!) Стратегия кэширования может дать вам коэффициент 100. Выяснив, что вам действительно не нужно делать вызов, вы получите Warp 10.

Это обычно заставляет меня задуматься о том, как организовать данные: какие частые операции являются потенциальными узкими местами или проблемами масштабируемости?

4
ответ дан 18 December 2019 в 05:11
поделиться

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

  • Use profiler
  • Используйте нетривиальный объем данных при тестировании. Если возможно, сделайте такое огромное количество данных.
  • Используйте разумные алгоритмы, когда ситуация становится напряженной.
  • Используйте профилировщик, чтобы проверить, что любая «оптимизация», которую вы сделали, действительно правильная, например недавнее фиаско с java jar, где Операция O (1) была выполнена как O (n).
4
ответ дан 18 December 2019 в 05:11
поделиться

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

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

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

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

5
ответ дан 18 December 2019 в 05:11
поделиться

Правила Клуба Оптимизации:

  1. Первое правило Клуба Оптимизации - вы не оптимизируете.
  2. Второе правило Клуба Оптимизации: вы не оптимизируете без измерения.
  3. Если ваше приложение работает быстрее, чем основной транспортный протокол, оптимизация завершена.
  4. Один фактор за раз.
  5. Нет маркетроидов, нет графиков маркетроидов.
  6. Тестирование будет продолжаться, пока оно должен.
  7. Если это ваша первая ночь в клубе оптимизации, вам нужно написать тестовый пример.

http://xoa.petdance.com/Rules_of_Optimization_Club

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

Правила № 6 и № 7: Всегда проводите тесты. Если вы оптимизируете, вы проводите рефакторинг, а не

14
ответ дан 18 December 2019 в 05:11
поделиться

Вы можете посмотреть, какие компиляторы ДЕЙСТВИТЕЛЬНО оптимизируют - многие компиляторы могут оптимизировать такие вещи, как хвостовая рекурсия, и большинство других незначительных оптимизаций по сравнению с ними тривиальны. Моя методология состоит в том, чтобы писать вещи так, чтобы они были как можно более читаемыми / управляемыми, а затем, если мне нужно, посмотрите, чтобы увидеть, нуждается ли сгенерированный код сборки в какой-либо оптимизации. Таким образом, не нужно тратить время на оптимизацию того, что не нужно оптимизировать.

1
ответ дан 18 December 2019 в 05:11
поделиться
2
ответ дан 18 December 2019 в 05:11
поделиться

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

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

std::vector<T> vec;
while (x) {
    vec.clear(); //instead of declaring the vector here
    ...
}

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

2
ответ дан 18 December 2019 в 05:11
поделиться

Я бы даже сказал, что для целых типов вместо умножения на 0,5 вы можете просто сдвинуть их на один бит вправо (не забывая сдвиг со знаком / без знака).

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

например:

Guid x = Guid.NewGuid(); 

и

Guid x; x = Guid.NewGuid();

оба переводятся в следующий CIL:

call        System.Guid.NewGuid
stloc.0   

Константа предварительно вычисляются такие выражения, как (4 + 5), а также конкатенации строк, такие как «Hello» + «World».

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

В моем случае наибольший прирост (иногда воспринимаемый) производительности был следующим:

  • Если вы получаете данные из базы данных или из Интернета,
3
ответ дан 18 December 2019 в 05:11
поделиться
  1. Записать читаемый код, показывающий намерение . Не выполняйте микрооптимизацию , а не - вы не сможете перехитрить JIT.
  2. Научитесь использовать профилировщик, например jvisualvm в Sun JDK, и используйте его.
4
ответ дан 18 December 2019 в 05:11
поделиться

Всегда хорошо помнить, что «стоит». Некоторые примеры C #:

  • Объединение строк всегда создает новую строку, поскольку строки неизменяемы. Следовательно, для повторяющихся конкатенаций более эффективен StringBuilder .

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

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

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


Относительно ваших "оптимизаций":

  • Я сомневаюсь, что арифметика с плавающей запятой ( * 0,5 ) быстрее, чем целочисленное деление ( / 2 ).

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

  • «требует 2 вызова в коде. "неверно.

8
ответ дан 18 December 2019 в 05:11
поделиться

РЕДАКТИРОВАТЬ Этот ответ первоначально появился в другом вопросе (который был объединен), где OP перечислял некоторые возможные методы оптимизации, которые, как он только что предположил, должны работать. Все они в значительной степени полагались на предположения (такие как x << 1 всегда быстрее, чем x * 2 ). Ниже я пытаюсь указать на опасность таких предположений.


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

В противном случае это - просто - не имеет - значения.

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

Также очень важно знать область, в которой вы работаете. Я пришел из биоинформатики и много делаю хардкорного алгоритма работы на C ++. Я часто имею дело с огромным объемом данных. В настоящий момент я создаю приложение на Java, и я съеживаюсь каждый раз, когда создаю копию контейнера, потому что я настроен чертовски избегать таких операций. Но для моего причудливого графического интерфейса Java эти операции совершенно тривиальны и никоим образом не заметны для пользователя. Ладно, мне просто нужно преодолеть себя.

Между прочим:

Инициализировать константы, когда вы их объявляете (если можете)…

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

17
ответ дан 18 December 2019 в 05:11
поделиться

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

3
ответ дан 18 December 2019 в 05:11
поделиться

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

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

Возьмите свою «оптимизацию»:

const int windowPosX = (screenWidth * 0.5) - (windowWidth * 0.5);

В мире нет серьезного компилятора, который не знал бы, что самый быстрый способ разделить на два - сдвинуть вправо на единицу. Умножение на 0,5 с плавающей запятой на самом деле дороже, потому что требует преобразования в числа с плавающей запятой и обратно и выполнения двух умножений (что дороже, чем сдвиги).

Но не верьте мне на слово. Посмотрите, что на самом деле делает компилятор. gcc 4.3.3 в 32-битной Ubuntu (-O3, -msse3, -fomit-frame-pointer) компилирует это:

int posx(unsigned int screen_width, unsigned int window_width) {
  return (screen_width / 2) - (window_width / 2);
}

в это:

00000040 <posx>:
  40:   8b 44 24 04             mov    eax,DWORD PTR [esp+0x4]
  44:   8b 54 24 08             mov    edx,DWORD PTR [esp+0x8]
  48:   d1 e8                   shr    eax,1
  4a:   d1 ea                   shr    edx,1
  4c:   29 d0                   sub    eax,edx
  4e:   c3    

Два сдвига (с использованием непосредственного операнда) и вычитание. Очень дешевый. С другой стороны, он компилирует это:

int posx(unsigned int screen_width, unsigned int window_width) {
  return (screen_width * 0.5) - (window_width * 0.5);
}

в следующее:

00000000 <posx>:
   0:   83 ec 04                sub    esp,0x4
   3:   31 d2                   xor    edx,edx
   5:   8b 44 24 08             mov    eax,DWORD PTR [esp+0x8]
   9:   52                      push   edx
   a:   31 d2                   xor    edx,edx
   c:   50                      push   eax
   d:   df 2c 24                fild   QWORD PTR [esp]
  10:   83 c4 08                add    esp,0x8
  13:   d8 0d 00 00 00 00       fmul   DWORD PTR ds:0x0
            15: R_386_32    .rodata.cst4
  19:   8b 44 24 0c             mov    eax,DWORD PTR [esp+0xc]
  1d:   52                      push   edx
  1e:   50                      push   eax
  1f:   df 2c 24                fild   QWORD PTR [esp]
  22:   d8 0d 04 00 00 00       fmul   DWORD PTR ds:0x4
            24: R_386_32    .rodata.cst4
  28:   de c1                   faddp  st(1),st
  2a:   db 4c 24 08             fisttp DWORD PTR [esp+0x8]
  2e:   8b 44 24 08             mov    eax,DWORD PTR [esp+0x8]
  32:   83 c4 0c                add    esp,0xc
  35:   c3                      ret

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

Подумайте об этом примере, когда вы испытывает соблазн выполнить такую ​​микрооптимизацию. Это не только преждевременно, но и может совсем не помочь (в данном случае значительно больно!)

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

40
ответ дан 18 December 2019 в 05:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: