Подтвердить что ты не робот

Когда использовать класс Partitioner?

Может ли кто-нибудь предложить типичные сценарии, где Partitioner класс, введенный в .NET 4.0, может/должен использоваться?

4b9b3361

Ответ 1

Класс Partitioner используется для более коротких параллельных исполнений. Если у вас много очень маленьких задач для параллельной работы, накладные расходы на вызов делегатов для каждого из них могут быть непомерно высокими. Используя Partitioner, вы можете переставить рабочую нагрузку в куски и каждый параллельный вызов работать на немного большем наборе. Класс абстрагирует эту функцию и может разбивать на основе фактических условий набора данных и доступных ядер.

Пример. Представьте, что вы хотите выполнить простой расчет, подобный этому, параллельно.

Parallel.ForEach(Input, (value, loopState, index) => { Result[index] = value*Math.PI; });

Это вызовет делегат для каждой записи в Input. Это добавит немного накладных расходов для каждого. Используя Partitioner, мы можем сделать что-то вроде этого

Parallel.ForEach(Partitioner.Create(0, Input.Length), range => {
   for (var index = range.Item1; index < range.Item2; index++) {
      Result[index] = Input[index]*Math.PI;
   }
});

Это уменьшит количество вызовов, поскольку каждый вызов будет работать с большим набором. По моему опыту это может значительно повысить производительность при распараллеливании очень простых операций.

Ответ 2

Чтобы распараллелить операцию с источником данных, одним из важных шагов является разделение источника на несколько разделов, к которым можно одновременно обращаться несколькими потоками. PLINQ и параллельная библиотека задач (TPL) предоставляют разделители по умолчанию, которые работают прозрачно при написании параллельного запроса или цикла ForEach. Для более сложных сценариев вы можете подключить свой собственный разделитель.

Подробнее здесь:

Ответ 3

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

Другим типом раздела, который следует учитывать, является разделение фрагментов. Этот тип разбиения также известен как алгоритм балансировки нагрузки, потому что рабочий поток редко сидит без дела, пока есть больше работы - это не относится к разделу диапазона.

Раздел chunk должен использоваться, когда работа имеет несколько состояний ожидания, имеет тенденцию требовать больше обработки для каждого элемента, или каждый элемент может иметь значительно разные рабочие времена обработки.

Одним из примеров этого может быть чтение в память и обработка 100 файлов с совершенно разными размерами. Файл 1K будет обрабатываться за меньшее время, чем файл размером 1 МБ. Если для этого используется раздел диапазона, то некоторые потоки могут некоторое время простаивать, потому что они обрабатывают файлы меньшего размера.

В отличие от раздела диапазона, нет способа указать количество элементов, которые будут обрабатываться каждой задачей, если только вы не написали свой собственный пользовательский разделитель. Еще один недостаток использования раздела chunk заключается в том, что может возникнуть конфликт, когда он вернется, чтобы получить еще один кусок, поскольку в этот момент используется эксклюзивная блокировка. Таким образом, очевидно, что раздел chunk не должен использоваться для коротких объемов работы с интенсивным процессором.

Разделитель секций по умолчанию начинается с размера блока размером 1 элемент на кусок. После того, как каждый поток обрабатывает три 1-элементных фрагмента, размер блока увеличивается до 2 элементов на кусок. После того, как три потока из 2 элементов обработаны каждым потоком, размер куска снова увеличивается до 3 элементов на кусок и так далее. По крайней мере, так оно работает в соответствии с Dixin Yan, (см. раздел раздел Chunk), который работает в Microsoft.

Кстати, хороший инструмент визуализатора в своем блоге выглядит как Concurrency Инструмент профиля Visualizer. docs для этого инструмента утверждают, что его можно использовать для определения узких мест производительности, недоиспользования ЦП, конфликтов потоков, миграции межсетевых потоков, задержки синхронизации, активность DirectX, области перекрытия ввода-вывода и другую информацию. Он предоставляет графические, табличные и текстовые представления данных, которые показывают взаимосвязь между потоками в приложении и системой в целом.

Другие ресурсы:

MSDN: пользовательские разделители для PLINQ и TPL

Часть 5: Параллельное программирование - Оптимизация PLINQ Джозефа Альбахари