Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

l8_nc

.pdf
Скачиваний:
13
Добавлен:
19.04.2015
Размер:
732.67 Кб
Скачать

Конструктивные изменения

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

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

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

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

Эффективно организовать потоки: избегать или удалять лишние блокировки.

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

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

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

© 2013 NetCracker Technology Corporation Confidential

21

Модификация кода

Развертывание циклов. Если у цикла очень короткое тело, то структура, образующая цикл, может обойтись дороже, чем сама циклическая операция. Избавьтесь от накладных расходов, сделав структуру плоской – замените цикл из 10 итераций на 10 последовательных операторов. Развертывание циклов может быть частичным, что бывает оправдано для больших циклов. Можно выполнить в каждой итерации четыре операции и каждый раз увеличивать счетчик цикла на четыре. Однако такой прием оказывается затруднителен, если количество итераций цикла не кратно количеству развернутых операций.

Встраивание кода. При выполнении коротких операций накладные расходы на вызов функции могут оказаться чрезмерными. С помощью разбиения кода на функции достигаются значительные преимущества: более понятный код, единообразие в результате многократного использования и возможность модификации в отдельной области. Однако для увеличения быстродействия можно освободиться от функций и объединить вызывающий код с вызываемым. Для этого есть несколько способов. При наличии соответствующей поддержки в языке можно сделать это в исходном коде (в C/C++ с помощью ключевого слова inline), при этом в значительной мере сохраняется читаемость кода. В противном случае придется соединять код самостоятельно, либо многократно копируя функцию, либо делая это с помощью препроцессора. Затруднительно встраивание обращений к рекурсивным функциям – как узнать, когда нужно остановиться? Попытайтесь заменить рекурсию другими алгоритмами. Встраивание часто открывает возможность дальнейшей оптимизации на уровне кода (ранее невозможной внутри границ функции).

Свертывание констант Вычисления с использованием констант можно проводить во время компиляции, что сокращает объем действий, проводимых на этапе выполнения. Простое выражение типа return 6+4; можно свести к return 10;. В результате упорядочения членов большого выражения можно свести вместе две константы, что позволит сократить выражение. Обычно программисты не пишут таких очевидных вещей, как return 6+4;. Однако такого рода выражения часто встречаются после расширений макросов.

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

Понижение прочности Речь идет о замене операции другой, которая выполняется быстрее. Это особенно эффективно на ЦП со слабой поддержкой арифметики. Например, заменить умножение или деление целых чисел на сдвиг или сложение; x/4 можно преобразовать в x>>2, если эта операция выполняется быстрее на вашем процессоре.

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

int first = (a * b) + 10; int second = (a * b) / c;

выражение (a * b) вычисляется два раза. Достаточно одного. Можно выделить общее выражение и заменить его на

int temp = a * b;

int first = temp + 10; int second = temp / c;

Удаление «мертвого» кода. Не пишите лишнего кода; уберите все, что не является необходимым для работы программы. Статический анализ покажет функции, которые никогда не вызываются, и участки кода, которые никогда не получают управления. Удалите их.

© 2013 NetCracker Technology Corporation Confidential

22

Зактыки с производительностью Java

© 2013 NetCracker Technology Corporation Confidential

23

Первый шаг

«я вижу, что метод foo() реализован неэффективно»

«по профайлеру видно, что метод bar() – горячий и занимает 5%» «по-моему, у нас тормозит БД, и нужно перейти с DB 1 на DB 2"

Правильный первый шаг:

Выбрать метрику

ops/sec, transactions/sec

время исполнения

время отклика

Убедиться в корректности метрики

релевантна (учитывает реальный сценарий работы приложения)

повторяема

© 2013 NetCracker Technology Corporation Confidential

24

Метрики

Throughput, Bandwidth. Количество работы, выполненное за единицу времени:

MB/sec

ops/sec, transactions/sec

FPS frames per second

Время...

...работы

Execution time: общее время исполнения

...отклика

Latency: время отдельной операции

Response time: задержка между стимулом и реакцией

...запуска

Startup time: время до начала работы

Time to performance: время до начала хорошей работы

Память

© 2013 NetCracker Technology Corporation Confidential

25

Что можно улучшить

Уровень системы

I/O (Сеть/Диск)

Операционная система

Процессор/память

Уровень JVM

Издержки работы самой JVM

Время GC

Уровень приложения

Количество потоков (мало или даже много)

Лишние блокировки, синхронизация

Алгоритмические проблемы (лишние вызовы, неэффективные структуры данных и алгоритмы)

Архитектурный уровень

Кеширование

Распределение нагрузки на нескольких узлов

Оптимизация взаимодействия между слоями

© 2013 NetCracker Technology Corporation Confidential

26

Уборка мусора

© 2013 NetCracker Technology Corporation Confidential

27

Уборка Мусора

Мусор – объект в памяти не достижимый из программного кода

Уборка бывает:

Подсчет ссылок

Транзитивное замыкание ссылок

Вообще не собирать

© 2013 NetCracker Technology Corporation Confidential

28

Подсчёт ссылок

«+»

Просто

Не требует остановки приложения

«-»

Не очищает циклические структуры

Дополнительная нагрузка на ЦП

Плохо сочетается с многопоточностью

© 2013 NetCracker Technology Corporation Confidential

29

Транзитивное замыкание ссылок

«+»

Есть корневые объекты (локальные и глобальные переменные). Все объекты достижимые – живые, не достижимые из корневых - мусор

«-»

Граф ссылок не должен меняться при обходе -> нужно тормозить предложение (stop- of-word)

© 2013 NetCracker Technology Corporation Confidential

30

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]