2015-08-22 2 views
6
.

. Я выполняю некоторые тесты нагрузки снова в приложении Spring, и теперь я немного запутался в конфигурации ThreadPoolTaskExecutor.Проблемы с размером бассейна SpringPoolTaskExecutor от Spring.

Документация внутренне используется ThreadPoolExecutor описывает corePoolSize, как «число потоков, чтобы держать в бассейне, даже если они находятся в режиме ожидания, [...]» и maximumPoolSize как «максимальное количество потоков, чтобы в бассейн".

Это означает, что maximumPoolSize ограничивает количество потоков в пуле. Но вместо этого предел кажется установленным corePoolSize. На самом деле я сконфигурировал только corePoolSize с 100, и пусть maximumPoolSize не сконфигурирован (это означает, что используется значение по умолчанию: Integer.MAX_VALUE = 2147483647).

Когда я запускаю нагрузочный тест, я вижу (просматривая журналы), что выполненный рабочий поток пронумерован от worker-1 до worker-100. Поэтому в этом случае размер пула потоков ограничен corePoolSize. Даже если я установил maximumPoolSize на 200 или 300, результат будет таким же.

Почему стоимость maximumPoolSize не влияет на мой случай?

@Bean 
public TaskExecutor taskExecutor() { 
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); 
    taskExecutor.setCorePoolSize(100); 
    taskExecutor.setThreadNamePrefix("worker-"); 
    return taskExecutor; 
} 

РЕШЕНИЕ

Я нашел решение в документации: "Если есть больше, чем corePoolSize, но меньше, чем maximumPoolSize нитей работает, новый поток создается только если очередь полный ". Размер очереди по умолчанию - Integer.MAX_VALUE. Если я ограничу очередь, все будет хорошо.

ответ

4

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

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

Попробуйте с corePoolSize ниже, чем количество ядер на вашей машине для подтверждения. Другой вариант - поместить Thread.sleep(1000) в код вашего работника и наблюдать за тем, как подсчитывают ваши работники.

EDIT:

Вы предложили использовать SimpleAsyncTaskExecutor в комментарии. Обратите внимание на этот раздел Spring Framework docs:

SimpleAsyncTaskExecutor Эта реализация не повторно использовать любые темы, а он начинает новый поток для каждого вызова. Однако он поддерживает ограничение параллелизма, которое блокирует любые вызовы , которые превышают лимит, до тех пор, пока слот не будет освобожден. Если вы ищете настоящий пул, см. Обсуждения SimpleThreadPoolTaskExecutor и ThreadPoolTaskExecutor ниже.

Так с SimpleAsyncTaskExecutor вы не Объединив на всех, и много ресурсов (циклы CPU включены) тратятся на создание и удаление Thread объектов, которые могут быть весьма дорогостоящей операцией.

Так что тип исполнителя SimpleAsyncTaskExecutor приносит больше вреда, чем пользы для тестирования нагрузки. Если вы хотите иметь больше работников, используйте больше машин. Наивно использовать только одну машину, если вы хотите иметь точный нагрузочный тест.

+0

Если я не определяю компонент пула потоков, «SimpleAsyncTaskExecutor» используется автоматически. При этом с исполнителем (без ограничений) результаты в 3 раза лучше. Если я установил размер основного пула «ThreadPoolTaskExecutor» на 20, максимальные используемые потоки равны 20. При меньшем размере пула результат хуже, это не может быть решением! – baymon

+0

Попробуйте поместить Thread.sleep (1000) в свой рабочий код. – luboskrnac

5

Я сделал некоторые испытания на ThreadPoolTaskExecutor и есть три вещи, которые вы должны понять:

  • corePoolSize
  • queueCapacity
  • MaxPoolSize

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

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

+0

Хорошая запись. Но, увидев, что пользователь уже дал ответ на свой пост. – Zico

+0

Я этого не видел, я только что присоединился и искал ответы на вопросы, и я получил это и ответил. Есть ли способ, по которому он может быть отмечен как ответ. Мы не будем терять время на уже ответившие вопросы. –

+0

@SomnathDe ваш ответ был намного лучше, объясняя это. Спасибо друг. – Ikthiander

Смежные вопросы