Есть два шага для оптимизации кода.
Во-первых, вам нужно выяснить, что медленно. Это профилирование, и, как вы можете догадаться, для этого обычно используется профилировщик. Большинство профилировщиков, как правило, просты в использовании. Вы запускаете свое приложение через профилировщик, и когда оно завершается, профилировщик покажет вам, сколько времени было потрачено на каждую функцию, как эксклюзивную (эта функция без учета времени, потраченного на вызов функции из этого), так и включительно (время, потраченное на эту функция, включая вызовы дочерних функций).
Другими словами, вы получаете большое дерево вызовов, и вам просто нужно выследить большие номера. Обычно у вас очень мало функций, занимающих более 10% времени выполнения. Так что найдите их, и вы знаете, что для оптимизации.
Обратите внимание, что профилировщик не является ни обязательным, ни обязательно подходом best . Удивительно простой, но эффективный подход заключается в том, чтобы просто запустить программу в отладчике и в несколько квази-случайных моментов приостановить выполнение и посмотреть на стек вызовов. Сделайте это всего пару раз, и у вас будет отличное представление о том, на что тратится ваше время выполнения. @ Майк Данлавей, который прокомментировал этот ответ, подробно описал этот подход в другом месте.
Но теперь, когда вы знаете, на что тратится время выполнения, наступает сложная часть, как оптимизировать код.
Конечно, наиболее эффективным подходом часто является высокоуровневый. Должна ли проблема быть решена таким образом? Это должно быть решено вообще? Может ли он быть решен заранее, а результат кэширован, чтобы он мог быть доставлен мгновенно, когда остальная часть приложения нуждалась в этом?
Существуют ли более эффективные алгоритмы решения проблемы?
Если вы можете применить такие высокоуровневые оптимизации, сделайте это, посмотрите, достаточно ли улучшилось это быстродействие, а если нет, снова профилируйте.
Рано или поздно вам, возможно, придется погрузиться в более низкоуровневые оптимизации. Это сложная территория, хотя. Современные компьютеры довольно сложны, и производительность, которую вы получаете от них, непроста. Стоимость ветки или вызова функции может широко варьироваться в зависимости от контекста. Добавление двух чисел может занять от 0 до 100 тактов в зависимости от того, были ли оба значения уже в регистрах ЦП, что выполняется в данный момент else и ряда других факторов. Таким образом, оптимизация на этом уровне требует (1) хорошего понимания того, как работает процессор, и (2) большого количества экспериментов и измерений. Вы можете легко внести изменение, которое, по вашему мнению, будет быстрее , но вы должны быть уверены в этом, поэтому измеряйте производительность до и после изменения.
Существует несколько общих практических правил, которые часто могут помочь при оптимизации:
I / O стоит дорого. Инструкции ЦП измеряются в долях наносекунды. Доступ к ОЗУ составляет от десятков до сотен наносекунд. Доступ с жесткого диска может занять десятки милли секунд. Так часто ввод / вывод замедляет работу вашего приложения.
Выполняет ли ваше приложение несколько больших операций ввода-вывода (чтение файла размером 20 МБ в одном большом фрагменте) или бесчисленное количество небольших операций (чтение байтов с 2052 по 2073 из одного файла, а затем считывание нескольких байтов из другого файла)? Меньшее количество операций чтения может ускорить ваш ввод-вывод в несколько тысяч раз.
Pagefaults также включает доступ с жесткого диска. Страницы в памяти должны быть помещены в файл подкачки, а выгруженные страницы должны быть считаны обратно в память. Если это часто случается, это будет медленно. Вы можете улучшить месторасположение своих данных, чтобы одновременно понадобилось меньше страниц? Вы можете просто купить больше оперативной памяти для хост-компьютера, чтобы избежать необходимости выкладывать данные? (Как правило, аппаратные средства дешевы. Обновление компьютера - это совершенно приемлемая оптимизация, но убедитесь, что обновление будет иметь значение. Считывание с диска не будет намного быстрее, если купить более быстрый компьютер. И если все уместится в ОЗУ на вашей старой системе нет смысла покупать ее с 8-кратным объемом ОЗУ)
Ваша база данных также использует доступ с жесткого диска. Так что вы можете избежать кэширования большего количества данных в оперативной памяти и только изредка записывать их в базу данных? (Конечно, есть риск. Что произойдет, если приложение выйдет из строя?
А потом есть все любимые, нити. Современный процессор имеет от 2 до 16 доступных процессорных ядер. Вы используете их все? Вы выиграли бы от их использования? Существуют ли длительные операции, которые могут выполняться асинхронно? Приложение запускает операцию в отдельном потоке, а затем может немедленно возобновить нормальную работу, а не блокировать ее до завершения операции.
Так что, в основном, используйте профилировщик, чтобы понять ваше приложение. Как он тратит время выполнения, где он тратится? Является ли потребление памяти проблемой? Каковы шаблоны ввода / вывода (как для жесткого диска, так и для доступа к сети, а также для любого другого типа ввода / вывода)?
ЦП просто постоянно работает или простоит в ожидании каких-то внешних событий, таких как ввод-вывод или таймеры?
А затем поймите как можно больше о компьютере, на котором он работает. Понять, какие ресурсы он имеет в наличии (кэш-память процессора, несколько ядер) и что каждый из них означает для производительности.
Это все довольно расплывчато, потому что уловки по оптимизации большого сервера баз данных будут очень отличаться от того, что вы бы сделали, чтобы оптимизировать какой-то алгоритм обработки больших чисел.