Хэшированные / Шардированные Блоки Действий


У меня есть постоянный поток определенных элементов, которые мне нужно обрабатывать параллельно, поэтому я использую 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 6

1 ответ:

Я думаю, что ваш подход является разумным, предполагая, что вы знаете, что хэш-коды будут хорошо распределены.

Если вы хотите иметь лучшую защиту от плохих дистрибутивов, вы можете использовать большее число ActionBlocks, ограничивая их общий уровень параллелизма с помощью одного пользовательского интерфейса.TaskScheduler общий для всех блоков. Вы можете найти такой планировщик в ParallelExtensionsExtras или на MSDN.