Вопрос

Есть ли встроенная поддержка в 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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top