Сколько ресурсов потребляют спящие и ожидающие потоки - PullRequest
19 голосов
/ 19 сентября 2008

Мне интересно, сколько стоит иметь много потоков в состоянии ожидания в java 1.6 x64.

Если быть более точным, я пишу приложение, которое работает на многих компьютерах и отправляет / получает данные от одного к другому. Мне удобнее иметь отдельный поток для каждой подключенной машины и задачи, например, 1) отправка данных, 2) получение данных, 3) восстановление соединения при его разрыве. Таким образом, учитывая, что в кластере N узлов, у каждой машины будет по 3 потока для каждого из N-1 соседей. Обычно это будет 12 машин, что соответствует 33 коммуникационным потокам.

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

Так есть ли какое-либо существенное влияние на производительность при наличии большого количества спящих потоков?

Ответы [ 5 ]

15 голосов
/ 19 сентября 2008

В большинстве случаев ресурсы, используемые спящим потоком, будут его стековым пространством. Известно, что использование модели 2-thread-per-connection, которая, на мой взгляд, аналогична описываемой вами, вызывает большие проблемы с масштабируемостью по этой самой причине, когда количество соединений увеличивается.

Я сам был в этой ситуации, и когда число соединений выросло выше 500 соединений (около тысячи потоков), вы, как правило, попадаете во множество случаев, когда вы получаете OutOfMemoryError, поскольку использование пространства стека потоков превышает максимальный объем памяти для одного процесса. По крайней мере, в нашем случае, который был в Java на 32-битном мире Windows. Я полагаю, что вы можете настроить вещи и продвинуться немного дальше, но, в конце концов, это не очень масштабируемо, поскольку вы тратите много памяти.

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

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

2 голосов
/ 19 сентября 2008

У нас была очень похожая проблема, прежде чем мы переключились на NIO, поэтому я буду повторять рекомендацию Liedmans перейти на эту платформу. Вы должны быть в состоянии найти учебник, но если вам нужны подробности, я могу порекомендовать Java NIO от Ron Hitchens.

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

1 голос
/ 19 сентября 2008

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

И если вам по какой-то причине нужно выполнить notifyAll (), то, конечно, вы пробуждаете множество дополнительных потоков - хотя вам может не потребоваться это в предложенной вами архитектуре.

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

1 голос
/ 19 сентября 2008

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

0 голосов
/ 29 ноября 2016

Из тестов, которые я проводил на C, Lua и Python, вы можете сделать свою собственную функцию сна или ожидания с очень маленькими строками кода, чтобы сделать простой легкий цикл. Используйте локальную переменную со временем в будущем, которого вы хотите достичь, и затем проверьте текущую временную метку в цикле while. Если вы находитесь в области действия, где вы работаете с fps, заставьте функцию ожидания запускаться один раз за кадр, чтобы сэкономить ресурсы. Для большей точности вам нужно использовать часы вместо метки времени, поскольку метка времени ограничена секундами. Чем больше строк кода вы добавляете в функцию ожидания, тем менее точной она становится и тем больше ресурсов она потребляет, хотя все, что меньше 10 строк, должно быть достаточно быстрым.

...