Масштабируемые пулы потоков с кражей работы - PullRequest
0 голосов
/ 09 мая 2018

В последнее время я изучаю различные архитектуры пула потоков. «Классическая» архитектура пула потоков обычно имеет N потоков и одну общую очередь задач. Я бы предположил, что эта архитектура масштабируется адекватно, пока отдельные задачи достаточно велики. Но для пула потоков, который выполняет много небольших задач, единственная очередь может стать узким местом.

Единственная архитектура, которую я нашел в своем исследовании, касающаяся этой архитектуры, - это архитектура "кражи работы" . Вместо одной общей очереди задач для каждого потока существует 1 «частная» очередь задач. Каждый рабочий поток выполняет задачи в своей собственной частной очереди, а затем, когда у него больше нет задач, он начинает случайным образом выбирать другие очереди и «красть» их задачи. Таким образом, это гарантирует, что все потоки всегда будут работать, пока существует больше задач, а также решает проблему узких мест в одной очереди.

Однако, одна проблема, которая никогда не упоминается, заключается в том, как такая очередь кражи работ может когда-либо гарантировать, что все потоки ЦП всегда будут использоваться так же, как гарантировала бы одна общая очередь. Проблема заключается в том, что в какой-то момент, когда больше нет работы, пул потоков должен sleep - то есть он должен ожидать семафор или переменную условия, пока не прибудет больше работы. В противном случае пул потоков будет бесконечно потреблять циклы ЦП, даже если никакие задачи не были поставлены в очередь. Но если пул потоков для кражи работы должен находиться в спящем режиме, вероятно, ему понадобится переменная семафора / условия, связанная с каждой очередью - в противном случае, если он использует общий семафор, мы возвращаемся к той же проблеме узкого места одной общей очереди - а именно, каждый поток производителя должен был бы бороться с сигнализацией общего семафора / условия var. Таким образом, это указывает на то, что пул потоков для кражи работ должен иметь одну переменную sempahore / condition на очередь.

Но если это так, то, похоже, нет никакой гарантии, что пул потоков когда-либо сможет гарантировать эффективное использование всех процессоров. Например, предположим, у нас есть 8 потоков и 8 очередей. Все потоки спят, за исключением потока [0], который занят выполнением задачи. Теперь потоку производителей не повезло, и он ставит другую задачу в очередь [0]. С общей очередью эта новая задача будет немедленно выполнена незанятым потоком. Но с рабочим пулом кражи остальные 7 потоков просто сидели бы без дела, потому что они никогда не были уведомлены о новой задаче и не могли знать, что есть еще работа.

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

Так как же решить эту проблему при проектировании пулов потоков для кражи работы?

...