SlideShare uma empresa Scribd logo
1 de 66
Сергей Ляджин
lyadzhin@devexperts.com
Оптимизация на халяву,
или как повысить производительность Java
Мы создаем качественное и эффективное ПО для
комплексной автоматизации брокерской, биржевой и финансовой
деятельности
Devexperts
Наша команда – это 300 профессионалов в области программирования,
тестирования и поддержки ПО
Офисы разработки расположены в Санкт-Петербурге и Ростове-на-Дону!
Офисы
- свободный график работы
- своя столовая
- комфортные рабочие места
- корпоративные мероприятия
- командировки по всему миру
- курсы английского языка
- неполная занятость и поддержка
в написании научных работ
Отличные условия работы!
План
The First Rule of Optimization:
Don't do it.
The Second Rule of Optimization (for experts only!):
Don't do it yet.
Michael A. Jackson
Кто быстрее?
• Задача – максимально быстро обойти
список объектов
• Участвуют:
• Заполняем числами последовательно
• Сложность обхода – O(N) операций
массив двойной-связный список
ArrayList LinkedList
Задача: Обход списка
• Обход ArrayList быстрее в 2-4 раза
Результаты тестов
• В списках хранятся не числа, а ссылки на объекты
Integer
• ArrayList - элемент массива + объект по ссылке
• LinkedList - ссылка на след. элемент + элемент по
ссылке + ссылка на объект + объект по ссылке
Реализация
• Collections.shuffle()
• Замедление в 5-10 раз
• В случае перемешанного LinkedList
получаем уже 1.5с
20M ArrayList LinkedList
Исходный 0.07с 0.27с
Перемешанный 0.61с 1.50с
Перемешиваем списки
• Объекты расположены последовательно
• Объекты расположены хаотично
Проанализируем
• Объем увеличивается, а скорость доступа
уменьшается
• Данные подгружаются блоками
очень
быстро
очень
медленно
Иерархия памяти
• Последующие элементы попадают в кэш CPU
• Элементы в кэш не попадают
Кэширование
• Итерирование по ArrayList в 2-4 раза
быстрее LinkedList
• Для ускорения итерации по ArrayList
добивайтесь локальности объектов-
элементов в памяти
Выводы: ArrayList vs. LinkedList
TALK IS CHEAP. SHOW ME THE
CODE.
Схема вычислений
A
B
С
A B CПрограмма:
Вычислительное устройство
Последовательное выполнение
A
B
С
B CПрограмма:
Вычислительное устройство
A
A
Последовательное выполнение
C
A
B
С
BПрограмма:
Вычислительное устройство
B
A
Последовательное выполнение
C
A
B
С
BПрограмма:
Вычислительное устройство
C
A
Последовательное выполнение
C
A
B
С
BПрограмма:
Вычислительное устройство
A
Последовательное выполнение
A
B
С
A B CПрограмма:
Вычислительное устройство
Конвейер
Конвейер
Ещё в начале XX века с помощью
конвейера Г. Форд в разы
увеличивал производительность
труда.
Вычислительная техника дошла
до этого только в 80х.
A
B
С
Программа:
Вычислительное устройство
Конвейер
A
CBA
Конвейер
C
A
B
С
A BПрограмма:
Вычислительное устройство
Конвейер
B A
Конвейер
A
B
С
A B CПрограмма:
Вычислительное устройство
Конвейер
C B A
Конвейер
A
B
С
A B CПрограмма:
Вычислительное устройство
Конвейер
C B A
Конвейер
A
B
С
A B CПрограмма:
Вычислительное устройство
Конвейер
C B A
Конвейер
A
B
С
B CПрограмма:
Вычислительное устройство
Конвейер
C B
A
Конвейер
A
B
С
CПрограмма:
Вычислительное устройство
Конвейер
C
A B
Конвейер
A
B
С
CПрограмма:
Вычислительное устройство
Конвейер
A B
Конвейер
Программа выполнена!
•Время выполнения одной команды
прежнее
•Общее количество выполненных
команд больше!
Время
Время
A B C
A
B
C
Последовательное выполнение
Выполнение с использованием конвейера
Анализ
•Время выполнения одной команды
прежнее
•Общее количество выполненных
команд больше!
A
B
С
A B CПрограмма:
Вычислительное устройство
Конвейер
A B C
Два прохода
A
B
С
Программа:
Вычислительное устройство
Конвейер
C
A
BACBA
Два прохода
A
B
С
AПрограмма:
Вычислительное устройство
Конвейер
C
B A
BACB
Два прохода
A
B
С
A BПрограмма:
Вычислительное устройство
Конвейер
C
C B A
BAC
Два прохода
A
B
С
A B CПрограмма:
Вычислительное устройство
Конвейер
C
A C B A
BA
Два прохода
A
B
С
A B CПрограмма:
Вычислительное устройство
Конвейер
A C
B A C B A
B
Два прохода
A
B
С
B CПрограмма:
Вычислительное устройство
Конвейер
A C
C B A C B
BA
Два прохода
A
B
С
B CПрограмма:
Вычислительное устройство
Конвейер
A C
C B A C B
BA
n < 0!
Два прохода
A
B
С
CПрограмма:
Вычислительное устройство
Конвейер
A C
C B A C B
BA
n < 0!
B
Работа проделана впустую!
Необходимо пересмотреть
порядок выполнения команд.
Два прохода
A
B
С
AПрограмма:
Вычислительное устройство
Конвейер
B CA B
Программа изменена.
Выполнение надо начинать заново.
Два прохода
A
B
С
Программа:
Вычислительное устройство
Конвейер
CA B
A
BA
Два прохода
A
B
С
AПрограмма:
Вычислительное устройство
Конвейер
CA B
B A
B
Два прохода
A
B
С
AПрограмма:
Вычислительное устройство
Конвейер
B CA B
C B A
Два прохода
A
B
С
AПрограмма:
Вычислительное устройство
Конвейер
B CA B
C B A
Два прохода
A
B
С
AПрограмма:
Вычислительное устройство
Конвейер
B CA B
C B A
Два прохода
A
B
С
AПрограмма:
Вычислительное устройство
Конвейер
B CA B
C B
Два прохода
A
B
С
AПрограмма:
Вычислительное устройство
Конвейер
B CA B
C
Два прохода
A
B
С
AПрограмма:
Вычислительное устройство
Конвейер
B CA B
Два прохода
Программа выполнена!
•Часть работы была сделана
впустую
•Как бороться? (позже)
Время
Время
A B C
A
B
C
Последовательное выполнение
Выполнение с использованием конвейера
A
B
C
Анализ
C
A
B
C
Время
Время
A B C
A
B
Последовательное выполнение
Выполнение с использованием конвейера
Выяснили, что порядок
выполнения будет другим
Анализ
C
A
B
C
Время
Время
A B C
A
B
Последовательное выполнение
Выполнение с использованием конвейера
Выполнять команды надо
было в другом порядке!
Анализ
Время
Время
A B C
A
B
Последовательное выполнение
Выполнение с использованием конвейера
Начнем выполнять сначала в
правильном порядке!
C
A
B
A
B
C
Можно было
делать
полезную
работу
Анализ
if(condition) {
A, C, F;
} else {
B;
if(condition) {
D, C, F;
} else {
E, G;
}
}
Возможны пути:
•S-ACF-E
•S-BDCF-E
•S-BEG-E
Предсказание переходов?
• Микрооптимизация
иногда оправдана
• Запас
производительности
может находится
за границами платформы
Выводы
Наглый алгоритм
Nagle’s алгоритм: ожидание подтверждения
доставки предыдущего сегмента перед отправкой
нового
write(1,2,3) write(4,5) write(6,7,8)
TCP Segment
1 2 3
TCP Segment
4 5
TCP ACK
for 1,2,3
TCP Segment
4 5 6 7 8
Network Pipe
t
Включаем TCP_NO_DELAY
setTcpNoDelay(true) выключает Nagle алгоритм
write(1,2,3) write(4,5) write(6,7,8)
Network Pipe
TCP Segment
1 2 3
TCP Segment
4 5
TCP Segment
6 7 8
t
Тест: Получение TCP сегментов
сервером
t
Message4
Message 5
Message1
Message 2
Message 3
t
Message 4Message1 Message2 Message 3
Nagle is
on
Nagle is
off
1 ms 2 ms
1 ms 2 ms
Nagle is
on
Nagle is off
Тест на быстром соединении
•Используйте TCP_NO_DELAY когда нужно
минимизировать задержки отправки каждого
сообщения
Latency vs Throughput
•Если требуется добиться максимальной
пропускной способности или медленная сеть,
лучше держать опцию TCP_NO_DELAY
выключенной
"We should forget about small efficiencies, say about 97%
of the time: premature optimization is the root of all evil"
Donald Knuth
Если Вам захотелось присоединиться к команде Devexperts,
пишите и звоните нам:
Тел.: (812) 438-16-26
E-mail: job@devexperts.com
Вакансии: hh.ru и itmozg.ru.
Наши новости: devexperts.com и ВКонтакте.
Контакт
Спасибо
Сергей Ляджин
lyadzhin@devexperts.com

Mais conteúdo relacionado

Semelhante a How to improve java performance

паскаль. часть1
паскаль. часть1паскаль. часть1
паскаль. часть1
igorm9so
 
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Ontico
 

Semelhante a How to improve java performance (20)

Переход с Objective-C на Swift — все ли так просто? / Олег Алексеенко (SuperJob)
Переход с Objective-C на Swift — все ли так просто? / Олег Алексеенко (SuperJob)Переход с Objective-C на Swift — все ли так просто? / Олег Алексеенко (SuperJob)
Переход с Objective-C на Swift — все ли так просто? / Олег Алексеенко (SuperJob)
 
Формальная верификация кода на языке Си
Формальная верификация кода на языке СиФормальная верификация кода на языке Си
Формальная верификация кода на языке Си
 
Formal verification of C code
Formal verification of C codeFormal verification of C code
Formal verification of C code
 
Формальная верификация кода на языке Си
Формальная верификация кода на языке СиФормальная верификация кода на языке Си
Формальная верификация кода на языке Си
 
пр 15.docx
пр 15.docxпр 15.docx
пр 15.docx
 
Андрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кодаАндрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кода
 
прак 15.docx
прак 15.docxпрак 15.docx
прак 15.docx
 
паскаль. часть1
паскаль. часть1паскаль. часть1
паскаль. часть1
 
Опыт тестирования API САПР платформы
Опыт тестирования API САПР платформыОпыт тестирования API САПР платформы
Опыт тестирования API САПР платформы
 
C#5 What's new?
C#5 What's new?C#5 What's new?
C#5 What's new?
 
Программируем быстрее с CodeRush
Программируем быстрее с CodeRushПрограммируем быстрее с CodeRush
Программируем быстрее с CodeRush
 
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
 
20110227 csseminar alvor_breslav
20110227 csseminar alvor_breslav20110227 csseminar alvor_breslav
20110227 csseminar alvor_breslav
 
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
 
что пришлось тестировать и о чем узнать при подготовке Linux версии pvs-studio
что пришлось тестировать и о чем узнать при подготовке Linux версии pvs-studioчто пришлось тестировать и о чем узнать при подготовке Linux версии pvs-studio
что пришлось тестировать и о чем узнать при подготовке Linux версии pvs-studio
 
Algo 01 part01
Algo 01 part01Algo 01 part01
Algo 01 part01
 
введение
введениевведение
введение
 
2 bdw.key
2 bdw.key2 bdw.key
2 bdw.key
 
Статический анализ кода: борьба с удорожанием ошибок
Статический анализ кода: борьба с удорожанием ошибокСтатический анализ кода: борьба с удорожанием ошибок
Статический анализ кода: борьба с удорожанием ошибок
 
Insane Byte' 2017
Insane Byte' 2017Insane Byte' 2017
Insane Byte' 2017
 

How to improve java performance

Notas do Editor

  1. Всем привет! Меня зовут Сергей Ляджин, я ведущий разработчик компании Devexperts и в ближайший час я расскажу вам о нескольких несложных трюках разработки высокопроизводительных систем на Java и не только. Мы делали этот доклад с моим коллегой Алексеем Николаенковым в прошлом году, получили положительные отзывы и по просьбам трудящихся выступаем на бис. Правда, Алексея сегодня, к сожаления, нету, но я постараюсь его заменить.
  2. Прежде чем мы перейдем к сути нашего доклада, позвольте вам немного рассказать о нашей компании. Компания Devexperts существует уже больше десяти лет. Мы специализируемся на разработке ПО для финансового рынка: брокеров и бирж. На наших продуктах работают крупнейшие американские и российские игроки этого рынка. Мы делаем десктопные, мобильные и веб GUI приложения, сложные распределенные и многопоточные серверные системы. Используем наиболее адекватные и современные технологии, постоянно обучаясь чему то новому и делясь опытом с коллегами.
  3. В нашей компании работает более 300 профессионалов своего дела. Это, конечно же, разработчики, тестировщики и специалисты по поддержке и внедрению. У нас дружный коллектив: мы вместе работаем и вместе отдыхаем – играем в настольные игры, воллейбол, футбол, теннис, катаемся на великах, ну и просто ходим пить пиво.
  4. Наш главный офис расположен, конечно же, в Санкт-Петебурге на Петроградке, но кроме того у нас есть офис в Ростове-на-Дону и офисы продаж в разных городах мира.
  5. Мы предлагаем нашим сотрудникам отличные условия работы. В наш соц. пакет входят, разумеется, полностью белая ЗП, своя столовая, ДМС, свободный график работы, удобные рабочие места. Мы поддерживаем студентов, предлагая им возможность учебных отпусков и поддержку в написании работ. В конце доклада я еще немного расскажу об открытых у нас на данный момент вакансиях, а наши дорогие HR -ы с удовольствием ответят на все ваши вопросы о компании и вакансии, если такие появятся.
  6. Ну что же. Давайте теперь перейдем к делу. Сейчас я расскажу вам о трех небольших оптимизационных трюках, покажу и объясню как и почему они работают. Можете мне задавать вопросы по ходу дела. Лучше каверзные, на которые я не знаю ответа, так будет веселее, и я тоже узнаю что-нибудь новенькое =)
  7. Первое с чего бы хотелось начать – это с двух простых правил оптимизации. На этом слайде представлены два известных правила оптимизации Майкла Джексона (нет, не того, о котором вы вероятно подумали). Первое правило оптимизации - не занимайтесь ей. Второе, если вы эксперт – не занимайтесь ей пока. Почему не заниматься и почему пока? Если вы еще не знаете, то подумайте до конца доклада, а в конце я вам расскажу =)
  8. И так, наша первая тема - казалось бы, простая и банальная задача, до боли знакомая любому Java , и не только, программисту – обход списков. У вас есть список объектов, вам надо перебрать все или часть его элементов, чтобы что-то найти или посчитать.
  9. Надеюсь, что вы все хорошо знаете интерфейс List из Java API и его реализации . Значит, наша цель – имея объект – список элементов, реализующий интерфейс List, максимально быстро обойти его. Берем две реализации интерфейса списка List, доступные в Java API изпокон веков – ArrayList и LinkedList. Внутри ArrayList находится массив ссылок на объекты – элементы списка, а внутри LinkedList находится двойной связный список, представленный набором объектов внутреннего класса LinkedList.Node , ссылающихся друг на друга и на элементы списка. Вначале мы последовательно заполним списки числами, а затем будем последовательно итерироваться по элементам этих списков, используя объект Iterator . Из теории известно, что обе реализации позволяют нам сделать обход списка за O(N) операций. Внимание, вопрос – есть ли разница на практике? Поднимите руки кто считает, что LinkedList проявит себя быстрее, а кто считает, что ArrayList? А остальные? ... &lt;&lt; Демонстрируем код. Создаем список, заполняем 5М элементами, дальше итерируемся по списку с помощью итератора. Делаем 100 раз, чтобы получить усредненное время выполнения. Выводим среднее время в миллисекундах. Первым в гонке участвует LinkedList. Затем ArrayList. Получаем в 2 раза быстрее. &gt;&gt;
  10. На диаграмме видим разницу во времени выполнения в зависимости от количества элементов в списке. Разница в 2-4 раза. На 20М элементов итерация по LinkedList занимает более четверти секунды, что может оказаться крайне существенным при обработке транзакции в высоконагруженной системе.
  11. Если посмотреть еще раз внимательно на код, то видно, что в список мы добавляем не числа примитивного типа int , а объекты класса Integer. Каждый раз когда добавляем – создаем новый объект. В структурах списков хранятся не числа, а ссылки на объекты. В случае ArrayList ссылки хранятся в массиве, в случае LinkedList ссылка хранится в поле объекта класса Node. Соотвественно при итерации по массиву мы читаем ссылку из элемента массива и достаем объект по ссылке. В случае LinkedList мы читаем ссылку на следующий элемент списка, достаем элемент списка по ссылке из него читаем ссылку на наш объект и только после этого достаем объект. Чуть больше операций. Но только ли в этом дело или может быть здесь есть чтото еще?
  12. Давайте попробуем немного усложнить наш эксперимент. До этого мы заполняли списки последовательно. Давайте теперь попробуем перемешать списки. В Java Collections API для этого есть стандартный метод Collections.shuffle(). Воспользуемся им и посмотрим что получается. LinkedList , а потом ArrayList. &lt; переключаемся на код &gt; Видим, что все замедлилось в 4 раза.
  13. Вернемся к нашим картинкам. При последовательно заполненных списках, каждый последующий элемент списка указывает на объект, который был создан в памяти сразу после текущего объекта. Что же произошло после того как мы вызвали shuffle? Теперь элементы списка указывают на объекты расположенные в случайном порядке. Как это может влиять на производительность обхода списка? Для ответа на этот вопрос давайте немного отойдем от списков в сторону и посмотрим на устройство памяти современного компьютера.
  14. В современнных компьютерах есть разные виды памяти с разными свойствами, есть регистры центрального процессора, его кэши, оперативная память и дисковая подсистема. Все эти виды памяти можно выстроить вот в такую пирамиду. Скорость доступа к памяти падает по мере спуска вниз по ней. Самыми быстрыми являются регистры центрального процессора, расположенные на том же кристалле, дальше идут кэши процессора и. А объем памяти наоброт увеличивается, регистры имеют разбер 64бита , кэши исчисляются мебагабайтами, оперативная память гигабайтами, а объемы жестких дисков уже терабайтами. Это всё замечательно скажете вы, но причем тут списки. Дело все в том, что данные с одного уровня памяти на другой подгружаются блоками, т.е. когда мы запрашиваем из оперативной памяти какой то элемент массива то мы подгружаем в кэш сразу кусок массива и при следующем обращении велика вероятность того, что нам не придется обращаться к оперативной памяти.
  15. Вернемся к нашим картинкам. При последовательно заполненных списках, каждый последующий элемент списка указывает на объект, который был создан в памяти сразу после текущего объекта. Что же произошло после того как мы вызвали shuffle? Теперь элементы списка указывают на объекты расположенные в случайном порядке. Как это может влиять на производительность обхода списка? Для ответа на этот вопрос давайте немного отойдем от списков в сторону и посмотрим на устройство памяти современного компьютера.
  16. Какие выводы из всего этого? Во-первых, мы увидели, что при любых обстоятельствах итерирование по ArrayList происходит в 2-4 раза быстрее. Во-вторых, если вы хотите выжать максимум, то добивайтесь локальности объектов – элементов ArrayList в памяти, т.е. добивайтесь того, что память под них была выделена в одном месте. Как это сделать? Создавать объекты единомоменты
  17. Программа представлена большим-большим графом и в каждой точке выполнения устройству нужно определить куда же выполнение пойдет дальше, чтобы прочитать вперед, чтобы конвеер хорошо работал. Для определения используются схемы предсказания переходов, они могут как совсем простыми (например, считать что переход всегда осуществиться), так и более сложными (например, собирающие и использующие статистику выполненных переходов) &lt;&lt; Давайте посмотрим на код и я попытаюсь объяснить на примере что же происходило &gt;&gt; &lt;&lt; А теперь давайте вспоним с чего мы начали говорить об этой задаче, а начали мы с того, что хорошее решение задачи может лежать совсем в другой плоскости, нежели вам кажется на первый взгляд &gt;&gt;
  18. Работая с TCP соединением, мало кто задумывается, что приходится иметь дело с “ наглым ” алгоритмом. Рассмотрим пример : установка сокетного соединения и отправка по нему сообщения – массива байт. Как вы знаете, данные по TCP отправляются пачками, так называемыми TCP- сегментами. Может показаться, что наши байтики полетят по сети сразу же после этого действия (write) – но это может оказаться и не так, ведь в действие вступает Nagle алгоритм (придуман by John Nagle ) который будет ждать полного заполнения сегмента данными (его default размер обычно 536 байт ) пока не получено подтверждение от принимающей стороны ( ACK- acknowledgement ) о получении отправленных ранее сегментов. После того, как подтверждение получено, наши данные отправляются по сети. Помните, что в java Nagle алгоритм включен по дефолту. Но не всех такой подход может устраивать, ведь если вам нужно отправить небольшие сообщения с минимальной задержкой (например котировки – очень важно каждую котировку доставить быстрее), хотелось бы такой алгоритм отключить. _____________________________________________________________________________________________________________ Важные моменты: Если в network pipe нет пакетов по которым еще не пришел ACK, то первый TCP сегмент отправится без задержки Сегмент отправляется без задержки при его полном заполнении By default наглый алгоритм включен ! Что делать если приходы сообщений происходит Упростить метрики измерений. Коммент о том что делает код, убрать время. + мысль о том как на халяву можно ускорить
  19. Java API по работе с сокетами предлагает нам метод для отключения Nagle алгоритма – называется setTcpNoDelay.
  20. Этот слайд нужно проскочить, если тест сработал. Давайте рассмотрим На хорошем соединении, число сообщений пришедших в одну миллисекунду меньше в 3 раза, а время обработки почти такое же. _______________________________________________________________________ Параметры доступа к серверу [email_address] pass: X7RRDvyv6vch Зайдя сказать java TcpServer Это запустит сервер, который будет слушать на порту 10000 Если процесс остался работать с прошлого раза, сервер не запустится сетуя на то что на порту 10000 уже кто-то слушает. Нужно грокнуть процесс найдя его через ps aux и kill pid _______________________________________________________________________
  21. _______________________________________________________________________ Параметры доступа к серверу [email_address] pass: X7RRDvyv6vch Зайдя сказать java TcpServer Это запустит сервер, который будет слушать на порту 10000 Если процесс остался работать с прошлого раза, сервер не запустится сетуя на то что на порту 10000 уже кто-то слушает. Нужно грокнуть процесс найдя его через ps aux и kill pid _______________________________________________________________________
  22. Даже если Вы не видите подходящей вакансии, все равно звоните/пишите и указывайте, что узнали о нас на ярмарке вакансий.