任务与障碍

Task vs Barrier

所以我的问题如下:我有一个要处理的项目列表,我想并行处理这些项目然后提交已处理的项目。

C# 中的障碍 class 允许我这样做 - 我可以 运行 线程并行处理项目列表,当调用 SignalAndWait 并且所有参与者都遇到障碍时我可以提交已处理的项目。

任务 class 也将允许我执行此操作 - 在 Task.WaitAll 调用中,我可以等待所有任务完成并提交已处理的项目。如果我理解正确,每个任务将 运行 在它自己的线程上,而不是在同一线程上并行执行一堆任务。

  1. 我对问题的两种用法的理解是否正确?
  2. 两者之间有什么优势吗?
  3. 有没有更好的混合解决方案(障碍和任务?)。

Is my understand correct on both usages for the problem?

我觉得你对Barrier有误解class。 The docs say:

A barrier is a user-defined synchronization primitive that enables multiple threads (known as participants) to work concurrently on an algorithm in phases.

屏障是一种同步原语。将它与可以并行计算的工作单元(例如 Task 进行比较是不正确的。

屏障可以通知所有线程等待,直到所有其他线程完成一些工作并检查该工作。就其本身而言,它没有并行计算能力,也没有背后的线程模型。

Is there any advantage between one over the other?

至于问题1,你看这无关紧要。

Is there any way a hybrid solution is better (barrier and tasks?).

对于您的情况,我完全不确定是否需要它。如果您只是想对一组项目并行执行 CPU 绑定计算,那么您有 Parallel.ForEach 正是为了这个目的。它将对一个可枚举对象进行分区并并行调用它们,然后阻塞直到计算完整个集合。

我没有直接回答你的问题,因为我认为使用障碍和任务只会让你的代码变得比它需要的更复杂。

我建议为此使用 Microsoft 的 Reactive Framework - 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(...) 方法允许您处理结果。

代码比使用任务或障碍简单得多。