Задача против Барьера
Поэтому моя проблема заключается в следующем: у меня есть список элементов для обработки, и я хотел бы обрабатывать элементы параллельно, а затем фиксировать обработанные элементы.
Класс барьера в C# позволит мне сделать это - я могу параллельно запускать потоки для обработки списка элементов, и когда вызывается SignalAndWait и все участники попадают в барьер, я могу зафиксировать обработанные элементы.
Класс Task также позволит мне сделать это - при вызове Task.WaitAll я могу дождаться завершения всех задач и зафиксировать обработанные элементы. Если я правильно понимаю, каждая задача будет выполняться в своем собственном потоке, а не в куче параллельных задач в одном потоке.
- Правильно ли мое понимание проблемы в обоих случаях?
- Есть ли какое-то преимущество между одним над другим?
- Есть ли способ гибридного решения лучше (барьер и задачи?).
2 ответа
Правильно ли мое понимание проблемы в обоих случаях?
Я думаю, у вас есть неправильное понимание Barrier
учебный класс. Документы говорят:
Барьер - это пользовательский примитив синхронизации, который позволяет нескольким потокам (известным как участники) работать над алгоритмом по фазам.
Барьер - это примитив синхронизации. Сравнивая его с единицей работы, которая может быть вычислена параллельно, например Task
не правильно
Барьер может сигнализировать всем потокам, чтобы они подождали, пока все остальные не завершили какую-либо работу, и проверили эту работу. Само по себе оно не имеет возможностей параллельных вычислений и никакой модели потоков.
Есть ли какое-то преимущество между одним над другим?
Что касается вопроса 1, вы видите, что это не имеет значения.
Есть ли способ гибридного решения лучше (барьер и задачи?).
В твоем случае я не уверен, что это вообще нужно. Если вы просто хотите параллельно выполнять вычисления с привязкой к ЦП для набора элементов, у вас есть Parallel.ForEach
именно для этой цели. Он разделит перечислимое и вызовет их параллельно, и заблокирует, пока не будет вычислена вся коллекция.
Я не отвечаю прямо на ваш вопрос, потому что считаю, что работа с барьерами и задачами просто делает ваш код более сложным, чем он должен быть.
Я бы предложил для этого использовать Reactive Framework от Microsoft - NuGet "Rx-Main", поскольку он просто делает всю проблему очень простой.
Вот код:
var query =
from item in items.ToObservable()
from processed in Observable.Start(() => processItem(item))
select new { item, processed };
query
.ToArray()
.Subscribe(processedItems =>
{
/* commit the processed items */
});
Запрос превращает список элементов в наблюдаемый, а затем обрабатывает каждый элемент, используя Observable.Start(...)
, Это оптимально запускает новые темы по мере необходимости. .ToArray()
берет последовательность отдельных результатов и изменяет ее в единый массив результатов. .Subscribe(...)
Затем метод позволяет обрабатывать результаты.
Код намного проще, чем использование задач или барьеров.