Настройки памяти с тысячами потоков

Я играю с JVM (Oracle 1.7 64 бит) на Linux-боксе (AMD 6 Core, 16 ГБ ОЗУ), чтобы посмотреть, как количество потоков в приложении влияет на производительность. Я надеюсь измерить, в какой момент переключение контекста снижает производительность.

Я создал небольшое приложение, которое создает пул выполнения потоков:

Executors.newFixedThreadPool(numThreads)

Я настраиваюnumThreads каждый раз, когда я запускаю программу, чтобы увидеть эффект, который она имеет.

Я тогда отправляюnumThread рабочие места (случаиjava.util.concurrent.Callable) в бассейн. Каждый увеличиваетAtomicInteger, выполняет некоторую работу (создает массив случайных целых чисел и перемешивает его), а затем некоторое время спит. Идея состоит в том, чтобы смоделировать вызов веб-службы. Наконец, задание повторно отправляется в пул, так что у меня всегда естьnumThreads рабочие места работают.

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

С несколькими тысячами потоков я могу обрабатывать до 400 000 заданий в минуту. Выше 8000 потоков результаты начинают сильно различаться, что говорит о том, что переключение контекста становится проблемой. Но я могу продолжать увеличивать количество потоков до 30 000 и по-прежнему получать более высокую пропускную способность (от 420 000 до 570 000 заданий в минуту).

Теперь вопрос: я получаюjava.lang.OutOfMemoryError: Unable to create new native thread с более чем около 31 000 рабочих мест. Я пробовал настройку-Xmx6000M что не помогает Я пытался играть с-Xss но это тоже не помогает.

Я прочитал этоulimit может быть полезным, но с увеличениемulimit -u 64000 ничего не изменилось

Для информации:

[root@apollo ant]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 127557
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1024
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Итак, вопрос № 1: Что мне нужно сделать, чтобы создать пул потоков большего размера?

Вопрос № 2: На каком этапе следует ожидать, что переключение контекста действительно уменьшит пропускную способность и приведет к остановке процесса?

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

// ( (n_cores x t_request) / (t_request - t_wait) ) + 1
// 300 ms wait, 10ms work, roughly 310ms per job => ideal response time, 310ms
// ideal num threads = 1860 / 10 + 1 = 187 threads
//
// results:
//
//   100 =>  19,000 thruput,  312ms response, cpu < 50%
//   150 =>  28,500 thruput,  314ms response, cpu 50%
//   180 =>  34,000 thruput,  318ms response, cpu 60%
//   190 =>  35,800 thruput,  317ms response, cpu 65%
//   200 =>  37,800 thruput,  319ms response, cpu 70%
//   230 =>  42,900 thruput,  321ms response, cpu 80%
//   270 =>  50,000 thruput,  324ms response, cpu 80%
//   350 =>  64,000 thruput,  329ms response, cpu 90%
//   400 =>  72,000 thruput,  335ms response, cpu >90%
//   500 =>  87,500 thruput,  343ms response, cpu >95%
//   700 => 100,000 thruput,  430ms response, cpu >99%
//  1000 => 100,000 thruput,  600ms response, cpu >99%
//  2000 => 105,000 thruput, 1100ms response, cpu >99%
//  5000 => 131,000 thruput, 1600ms response, cpu >99%
// 10000 => 131,000 thruput, 2700ms response, cpu >99%,  16GB Virtual size
// 20000 => 140,000 thruput, 4000ms response, cpu >99%,  27GB Virtual size
// 30000 => 133,000 thruput, 2800ms response, cpu >99%,  37GB Virtual size
// 40000 =>       - thruput,    -ms response, cpu >99%, >39GB Virtual size => java.lang.OutOfMemoryError: unable to create new native thread

Я интерпретирую их как:

1) Даже если приложение спит в течение 96,7% времени, все равно остается много переключений потоков. 2) Переключение контекста измеримо и отображается во времени отклика.

Здесь интересно то, что при настройке приложения вы можете выбрать приемлемое время ответа, скажем, 400 мс, и увеличивать количество потоков, пока не получите это время ответа, которое в этом случае позволит приложению обрабатывать около 95 тысяч запросов минута.

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

Ответы на вопрос(2)

Ваш ответ на вопрос