Какие хорошие методы оптимизации кода? - PullRequest
5 голосов
/ 22 мая 2009

Я хотел бы понять хорошие методы и методологию оптимизации кода.

  1. Как мне избежать преждевременной оптимизации, если я уже думаю о производительности.
  2. Как мне найти узкие места в моем коде?
  3. Как мне убедиться, что со временем моя программа не станет медленнее?
  4. Каковы некоторые распространенные ошибки производительности, которых следует избегать (например, я знаю, что в некоторых языках плохо возвращаться в пределах части catch блока try {} catch {}

Ответы [ 21 ]

3 голосов
/ 30 августа 2009

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

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

например:

Guid x = Guid.NewGuid(); 

а также

Guid x; x = Guid.NewGuid();

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

call        System.Guid.NewGuid
stloc.0   

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

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

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

  • Если вы выбираете данные из базы данных или интернета, используйте отдельный поток
  • Если вы загружаете большие XML-файлы, делайте это в отдельном потоке.

Конечно, это только мой опыт работы с C #, но операции ввода / вывода являются общими узкими местами.

3 голосов
/ 30 августа 2009

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

2 голосов
/ 30 августа 2009

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

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

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

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

2 голосов
/ 30 августа 2009
2 голосов
/ 22 мая 2009

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

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

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

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

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

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

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

1 голос
/ 30 августа 2009

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

1 голос
/ 22 мая 2009

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

Мои лучшие хиты:

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

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

0 голосов
/ 04 марта 2015

Сводка методов оптимизации кода (не зависит от языка) на github (ps я автор)

Outline:

  1. Общие принципы (т. Е. Кэширование, непрерывные блоки, отложенная загрузка и т. Д.)
  2. Низкий уровень (двоичные форматы, арифметические операции, распределение данных и т. Д.)
  3. Оптимизация, не зависящая от языка (реорганизация выражений, упрощение кода, оптимизация цикла и т. Д.)
  4. Базы данных (отложенная загрузка, эффективные запросы, избыточность и т. Д.)
  5. Интернет (минимальные транзакции, компактификация и т. Д.)
  6. Ссылки
0 голосов
/ 13 февраля 2012

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

Насколько важна оптимизация и как она повлияет на удобочитаемость и удобство обслуживания?

Как мне найти узкие места в моем коде?

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

В противовес популярным подходам, профилирование после написания программы или при наличии проблемы наивно - это все равно, что добавлять соус в плохо приготовленную еду, чтобы скрыть неприятности. Это также можно сравнить с различием между человеком, который всегда просит решения, а не фактически определяет причину (и узнает, почему в процессе). Если вы внедрили программу, затем потратили время на профилирование, затем внесли простые исправления и ускорили ее на 20% в процессе… обычно это не «хорошая» реализация, если важны производительность и использование ресурсов, поскольку все мелкие проблемы, будет накоплен высокий шум на выходе профилировщика. Хорошая реализация, как правило, в 5, 10 или даже 25 раз лучше, чем реализация случайного конструктора.

Как мне убедиться, что со временем моя программа не станет медленнее?

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

Каковы некоторые распространенные ошибки производительности, которых следует избегать (например, я знаю, что в некоторых языках плохо возвращаться, находясь внутри части catch блока try {} catch {}

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

0 голосов
/ 22 мая 2009

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...