Parallel.ForEach 和 await ForEachAsync 之间的差异

Differences between Parallel.ForEach and await ForEachAsync

是否有任何理由在任何情况下选择 Parallel.ForEach 而不是 await ForEachAsync(反之亦然)?或者它们实际上是一样的?

await collection.ForEachAsync( m => { m.DoSomething(); } );

VS

Parallel.ForEach( collection, m => { m.DoSomething(); } );

他们根本不是 'virtually the same'。

当您使用 Parallel class 中的函数时,例如 Parallel.ForEach() 您正在调用一些操作,其中该操作被分解为多个较小的操作,每个操作执行不同的线程(又名多线程)。

另一方面,

ForEachAsync 不一定是多线程的。它是异步的,异步操作不是多线程的(它们可以,但不一定,这取决于实现)。

我强烈建议阅读以下内容 ,其中更详细地介绍了该主题。

至于你

的问题

Is there any reason to choose Parallel.ForEach instead of await ForEachAsync in any situation

答案肯定是有这样做的理由,但为了确定您将使用其中一种方案的哪种情况,您必须同时了解它们。

这是一个简单的例子:

您有一个对象集合,您想要遍历它们并执行某种操作。你关心这些动作发生的顺序吗?如果是这样,请不要使用 Parallel.ForEach(),因为无法保证它们的调用顺序(由于其多线程特性)。

编辑:

在您的示例中,这完全取决于 collection 中有多少项目以及 DoSomething() 的流程繁重程度。

这是因为 Parallel.ForEach() 不是免费的 。需要做出权衡。设置多线程环境需要时间,如果 collection 很小 and/or DoSomething() 不会花费 too 长,那么设置所花费的时间在单线程异步操作中使用这些线程会更好(通常更快)。

另一方面,如果 collection 很大 and/or DoSomething() 是一个流程繁重的任务,那么 Parallel.ForEach() 绝对是最高效的选择。

这完全取决于线程 假设您有以下 class

public class person
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }

这是您的主要内容 Class

List<person> persons = new List<person>()
            {
                new person{ ID = 1,Name="Ali"}
                ,new person{ ID = 2,Name="Gorge"}
                ,new person{ ID = 3,Name="Alex"}
                ,new person{ ID = 4,Name="Liz"}
                ,new person{ ID = 5,Name="Scott"}
                ,new person{ ID = 6,Name="Abby"}
                ,new person{ ID = 7,Name="Sarah"}
            };

            Parallel.ForEach(persons, (p) =>
            {
                Console.WriteLine($"Id : {p.ID} ,Name : {p.Name}");
            });

当你 运行 这段代码时,列表项将被拆分到 diff 线程上,并且代码不会 运行ning 按顺序排列,正如你在以下输出中看到的那样,我得到了打印与我的原始列表不同的顺序

我在这里 运行再次使用相同的代码,但我得到了不同的结果

由于线程的原因,编译器划分为线程数和每个列表 运行 分配给它的项目 下图显示了差异线程

但是当你运行下面的代码

List<person> persons = new List<person>()
            {
                new person{ ID = 1,Name="Ali"}
                ,new person{ ID = 2,Name="Gorge"}
                ,new person{ ID = 3,Name="Alex"}
                ,new person{ ID = 4,Name="Liz"}
                ,new person{ ID = 5,Name="Scott"}
                ,new person{ ID = 6,Name="Abby"}
                ,new person{ ID = 7,Name="Sarah"}
            };

            await persons.ForEachAsync(async p => Console.WriteLine($"Id : {p.ID} ,Name : {p.Name}"));

您只有一个线程,如图所示

加上数据打印 将始终 运行ning 以与您的列表 相同的顺序

我希望这个答案能解释其中的区别!

Is there any reason to choose Parallel.ForEach instead of await ForEachAsync in any situation (or vice-versa)?

Parallel.ForEach 用于同步代码。它的委托必须是同步的,它被同步调用。

ForEachAsync 不是标准算法。有几种不同的实现,但通常它们试图混合异步和并行。他们不得不放弃Parallel.ForEach的一些自平衡方面。绝大多数代码不需要ForEachAsync;大多数代码是 异步 并行。