Разумное количество потоков для пула потоков, выполняющих запросы веб-службы

StackOverflow https://stackoverflow.com/questions/1028707

Вопрос

При создании объекта FixedThreadPool Executor в Java вам нужно передать аргумент, описывающий количество потоков, которые Исполнитель может выполнять одновременно. Я строю сервисный класс, в обязанности которого входит обработка большого количества телефонных номеров. Для каждого номера телефона мне нужно запустить веб-сервис (это мое узкое место), а затем сохранить ответ в хэш-карте.

Чтобы сделать это узкое место менее вредным для производительности моего сервиса, я решил создать класс Worker, который выбирает необработанные элементы и обрабатывает их. Класс Worker реализует интерфейс Runnable, и я запускаю Workers с помощью Executor.

Количество рабочих, которые могут быть запущены одновременно, зависит от размера Executor FixedThreadPool. Какой безопасный размер для ThreadPool? Что может произойти, когда я создаю FixedTheradPool с большим числом в качестве аргумента?

Это было полезно?

Решение

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

Другие советы

Что-то, что можно рассмотреть, смотрит на

Runtime.getRuntime().availableProcessors()

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

Я где-то читал, что оптимальное количество потоков - это количество ядер * 25. Похоже, что .NET использует это по умолчанию для ThreadPool. Однако, если у вас большое количество вызовов веб-служб, вам лучше использовать один поток и проверить список вызовов веб-служб для получения ответа. После получения ответа просто обработайте запись и удалите ее из списка.

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

Если у вас есть доступ dev к веб-службе, рассмотрите возможность создания пакетной функции для проверки нескольких телефонных номеров за один звонок.

В более новой версии .NET есть ThreadPool, который может увеличиваться и уменьшаться в зависимости от собственного профиля производительности. К сожалению, версия Java либо исправлена, либо увеличивается до предела в зависимости от поступающей работы.

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

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

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

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

В соответствии с этими предположениями вы не сможете максимизировать пропускную способность многоядерного процессора для пула потоков любого размера. Для достижения максимального количества транзакций в секунду вы должны разбить поток на модель соединения. Найдите упомянутый ранее неблокирующий ввод-вывод (NIO) или реализацию Java шаблона токена асинхронного завершения (IO-завершение в Windows).

Обратите внимание, что стековая память, зарезервированная для каждого созданного потока, фактически является просто зарезервированным адресным пространством , а не фактически выделенной или выделенной памятью. По мере того, как стек пытается расти, генерируются исключения, в результате чего память стека фиксируется по требованию. Следствием этого является то, что это действительно актуально только для 32-битных менеджеров памяти. Для 64-битной памяти у вас есть огромное адресное пространство, даже если вы зарезервировали только небольшую часть этого пространства физической памятью. По крайней мере, я так понимаю, что Windows работает, я не уверен в мире Unix.

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

Этот размер стека настраивается через -Xss (аналогично -Xmx и т. д.). Я считаю, что по умолчанию 512Kb на поток. На данный момент я не могу найти какого-либо авторитетного, чтобы подтвердить это.

Интересно, лучше ли вам использовать NIO, а не потоки, поскольку вашим ограничивающим фактором будет сервер веб-службы + узкое место в сети, а не клиентский ЦП.

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top