Хэшированные / Шардированные Блоки Действий
У меня есть постоянный поток определенных элементов, которые мне нужно обрабатывать параллельно, поэтому я использую TPL Dataflow
. Загвоздка в том, что элементы, имеющие один и тот же ключ (подобно словарю), должны обрабатываться в порядке FIFO и не быть параллельными друг другу (они могут быть параллельны другим элементам с разными значениями).
Выполняемая работа очень привязана к процессору с минимальными асинхронными блокировками, поэтому моим решением было создать массив ActionBlock<T>
s размером Environment.ProcessorCount
без параллелизма и пост к ним в соответствии со значением ключа GetHashCode
.
Создание:
_actionBlocks = new ActionBlock<Item>[Environment.ProcessorCount];
for (int i = 0; i < _actionBlocks.Length; i++)
{
_actionBlocks[i] = new ActionBlock<Item>(_ => ProcessItemAsync(_));
}
Использование:
bool ProcessItem(Key key, Item item)
{
var actionBlock = _actionBlocks[(uint)key.GetHashCode() % _actionBlocks.Length];
return actionBlock.Post(item);
}
Итак, мой вопрос в том, является ли это лучшим решением моей проблемы? Я вредю производительности / масштабируемости? Я что-то упустил?1 ответ:
Я думаю, что ваш подход является разумным, предполагая, что вы знаете, что хэш-коды будут хорошо распределены.
Если вы хотите иметь лучшую защиту от плохих дистрибутивов, вы можете использовать большее число
ActionBlock
s, ограничивая их общий уровень параллелизма с помощью одного пользовательского интерфейса.TaskScheduler
общий для всех блоков. Вы можете найти такой планировщик в ParallelExtensionsExtras или на MSDN.