Параллельная операция дозирования
-
26-09-2019 - |
Вопрос
Есть ли встроенная поддержка в TPL (Paral Carallel-library) для дозирования операций?
Я недавно играл с рутиной для выполнения замены персонажа на массиве символов с помощью таблицы поиска, т.е. транслитерацию:
for (int i = 0; i < chars.Length; i++)
{
char replaceChar;
if (lookup.TryGetValue(chars[i], out replaceChar))
{
chars[i] = replaceChar;
}
}
Я мог видеть, что это может быть тривиально распараллелировано, поэтому прыгнул с первым ударом, который я знал, будет работать хуже, так как задачи были слишком тонкой:
Parallel.For(0, chars.Length, i =>
{
char replaceChar;
if (lookup.TryGetValue(chars[i], out replaceChar))
{
chars[i] = replaceChar;
}
});
Затем я переработал алгоритм, чтобы использовать дозирование, чтобы работа была разорвана на разные резьбы в менее мелкозернистых партиях. Это использовало нити, как ожидалось, и у меня возле линейной скорости.
Я уверен, что должна быть встроенная поддержка дозирования в TPL. Что такое синтаксис, и как мне это использовать?
const int CharBatch = 100;
int charLen = chars.Length;
Parallel.For(0, ((charLen / CharBatch) + 1), i =>
{
int batchUpper = ((i + 1) * CharBatch);
for (int j = i * CharBatch; j < batchUpper && j < charLen; j++)
{
char replaceChar;
if (lookup.TryGetValue(chars[j], out replaceChar))
{
chars[j] = replaceChar;
}
}
});
Обновлять
После использования ответа @ Oliver и замена Parallel.For
с А. Parallel.Foreach и частично Код выглядит следующим образом:
const int CharBatch = 100;
Parallel.ForEach(Partitioner.Create(0, chars.Length, CharBatch), range =>
{
for (int i = range.Item1; i < range.Item2; i++)
{
char replaceChar;
if (lookup.TryGetValue(chars[i], out replaceChar))
{
chars[i] = replaceChar;
}
}
});
Решение
Для лучшего получения головы, вы должны получить Шаблоны для параллельного программирования: понимание и применение параллельных шаблонов с помощью .NET Framework 4. Отказ Это отличный источник и объясняет общие способы использования TPL.
Посмотрите на страницу 26 (очень маленькие циклические тела). Там вы найдете этот пример:
Parallel.ForEach(Partitioner.Create(from, to), range =>
{
for (int i = range.Item1; i < range.Item2; i++)
{
// ... process i
}
});
Так что отсутствующий кусок, который вы ищете System.Concurrent.Collections.Partitioner
.