2010-10-27 2 views

ответ

26

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

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

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

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

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

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

+8

Диапазон значений по умолчанию - один для Partitioner.Create(). Таким образом, раздел для обоих примеров кода одинаковый. Если Partitioner.Create (0, Input.Length, i); где i> 1, он все равно будет иметь такое же количество потоков. – Pingpong

2

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

Подробнее here:

+2

Я хотел бы добавить к этому: Вообще говоря * вы * не использовать его. PLINQ делает, и вам, вероятно, удастся с разделителями по умолчанию. –

1

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

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

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

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

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

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

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

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

MSDN: Custom Partitioners for PLINQ and TPL

Part 5: Parallel Programming - Optimizing PLINQ Джозеф Albahari

Смежные вопросы