Параллелизм в среде Java EE - PullRequest
1 голос
/ 24 января 2011

Цель

Моя цель - лучше понять, как параллелизм в среде Java EE и как его лучше использовать.

Общие вопросы

Давайте рассмотрим типичный контейнер сервлетов (tomcat).) как пример.Для каждого запроса он использует 1 поток для его обработки.Пул потоков настроен так, что в нем может быть не более 80 потоков.Давайте также возьмем простое веб-приложение - оно выполняет некоторую обработку и связь с БД во время каждого запроса.

В пиковое время я вижу 80 параллельно работающих потоков (+ несколько других потоков инфраструктуры).Давайте также предположим, что я запускаю его в экземпляре m2.large EC2.

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

Сравнение актеров

Наличие 80+ потоков на 4-х ядерном ЦП мне не кажется здоровым.Особенно, если большинство из них заблокированы каким-либо вводом-выводом (БД, Файловая система, Сокет) - они просто потребляют драгоценные ресурсы.Что если мы отсоединим запрос от потока и будем иметь только разумное количество потоков (например, 8) и просто отправим им задачи обработки.Конечно, в этом случае IO также должен быть неблокирующим, чтобы я получал события, когда некоторые нужные мне данные доступны, и отправляю событие, если у меня есть какие-то результаты.

Насколько я понимаюАктерская модель все об этом.Актеры не связаны с потоками (по крайней мере, в Akka и Scala).Итак, у меня есть разумный пул потоков и куча актеров с почтовыми ящиками, которые содержат задачи обработки.

Теперь вопрос - как модель актора сравнивается с традиционной моделью потока на запрос с точки зрения производительности, накладных расходов планировщика ипотребление ресурсов (ОЗУ, ЦП)?

Пользовательские потоки

У меня есть несколько запросов (только несколько), которые обрабатывают слишком много времени.Я оптимизировал код и все алгоритмы, добавил кеши, но это все еще занимает слишком много времени.Но я вижу, что алгоритм можно распараллелить.Это естественно вписывается в модель актера - я просто делю свою большую задачу на несколько задач, а затем как-то объединяю результаты (при необходимости).Но в модели потоков на запрос мне нужно порождать свои собственные потоки (или создавать свой небольшой пул потоков).Насколько я знаю, это не рекомендуется для практики в среде Java EE.И, с моей точки зрения, он не вписывается в модель потока на запрос.Возникает вопрос: насколько большим должен быть размер пула потоков?Даже если я сделаю это разумно с точки зрения аппаратного обеспечения, у меня все еще есть эта куча потоков, управляемых контейнером сервлета.Управление потоками становится децентрализованным и сходит с ума.

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

Ответы [ 2 ]

3 голосов
/ 24 января 2011

Наличие 80+ потоков на 4-х ядерном процессоре мне не кажется здоровым.Особенно, если большинство из них заблокированы каким-либо вводом-выводом (БД, Файловая система, Сокет) - они просто потребляют драгоценные ресурсы.

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

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

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

Никогда не слышал об этом (но я не претендую на то, чтобы быть лучшим экспертом по Java EE).ИМХО, нет ничего плохого в параллельном выполнении задач, связанных с одним запросом, например, ThreadPoolExecutor .Обратите внимание, что эти потоки не являются потоками обработки запросов, поэтому они напрямую не влияют на пул потоков, используемый контейнером EJB.Разумеется, за исключением того, что они конкурируют за одни и те же ресурсы, поэтому они могут замедлить или полностью остановить другие потоки обработки запросов в неосторожной установке.

, что является лучшим способом справиться с этими ситуациями в потоке.Модель для каждого запроса?

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

1 голос
/ 24 января 2011

Весь смысл Java EE состоит в том, чтобы включить в инфраструктуру общие архитектурные проблемы, такие как безопасность, состояние и параллелизм, и позволить вам предоставить кусочки бизнес-логики или сопоставления данных вместе с проводкой для их соединения. Таким образом, Java EE преднамеренно скрывает неприятные моменты параллелизма (блокировки для изменяемого состояния чтения / записи) в структуре.

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

Нет ничего плохого в том, чтобы на производственной коробке было 80 потоков. Большинство будет заблокировано или ожидает ввода / вывода, что нормально. Существует (настраиваемый) пул потоков, выполняющих фактические вычисления, и Java EE предоставит вам внешние ловушки для настройки этих ручек.

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

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

Как правило, при определении размеров связанных с вычислениями пулов потоков необходимо, чтобы они были приблизительно равны N ядер + 2. Многие фреймворки автоматически устанавливают размер. Вы можете использовать Runtime.getRuntime (). AvailableProcessors (), чтобы получить N. Если ваша проблема разлагается в алгоритме стиля «разделяй и властвуй» и количество элементов данных велико, я настоятельно рекомендую проверить функцию fork / join, которая может быть теперь используется как отдельная библиотека и будет частью Java 7.

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

У меня есть список актеров, fork / join и некоторые другие модели параллелизма, которые могут вас заинтересовать: http://tech.puredanger.com/2011/01/14/comparing-concurrent-frameworks/

...