PLINQ не улучшает производительность

Я написал LINQ, чтобы узнать частоты уникальных символов из текстового файла. Я также преобразовывал свой первоначальный результат в объект с помощью select. Окончательный результат получается в виде списка. Ниже приведен запрос, который я использовал.

charNodes = inputString.GroupBy(ch => ch)
            .Select((ch) => new TNode(ch.Key.ToString(),ch.Count()))
            .ToList<TNode>();

У меня запущена четырехъядерная машина, и вышеупомянутый запрос выполнялся за 15 мс. Но странно, что когда я выполнял тот же запрос, потребовалось больше времени.

charNodes = inputString.GroupBy(ch => ch).AsParallel
            .Select((ch) => new TNode(ch.Key.ToString(),ch.Count()))
            .ToList<TNode>();

Наихудший случай был со следующим запросом, который занял около 83мс

charNodes = inputString.AsParallel().GroupBy(ch => ch)
                               .Select((ch) => new TNode(ch.Key.ToString(), ch.Count()))
                               .ToList<TNode>();

Что здесь не так?

2 ответа

Решение

Когда возникает вопрос такого типа, ответ всегда один и тот же: издержки PLINQ выше, чем выигрыш.

Это происходит потому, что рабочие элементы чрезвычайно малы (группировка по символу или создание нового объекта из тривиальных входных данных). Это работает намного лучше, когда они больше.

Трудно сказать, что там происходит, строго основываясь на коде, который вы предоставили.

TPL использует потоки пула потоков. Пул потоков запускается примерно с 10 запущенными потоками. Если вам нужно больше потоков, то пул потоков будет создавать новые примерно раз в секунду, если нужен новый поток. Если ваш цикл привел к более чем 10 параллельным операциям, ему нужно было бы потратить время на раскручивание нового потока. Исправление: количество потоков, необходимое параллельному циклу, отбирает у доступных потоков в пуле потоков. Пул потоков пытается сохранить минимальное количество доступных потоков в этом пуле, если он замечает, что потоки занимают слишком много времени, он раскручивает новые для компенсации - что требует ресурсов. Многие части фреймворка используют пул потоков, так что есть множество возможностей, которые могут создавать нагрузку на пул потоков. Начало потока довольно дорого.

Другое, возможно, заключается в том, что если количество ваших итераций было больше, чем количество доступных процессоров, это привело к значительному переключению контекста. Переключение контекста стоит дорого и влияет на нагрузку на ЦП, а также на скорость, с которой ОС может переключаться между потоками.

Если вы предоставите более подробную информацию, например, входные данные, я могу предоставить более подробную информацию в ответе.

Другие вопросы по тегам