Parallel.ForEach 和等待 ForEachAsync 之间的差异

Rag*_*ock 16 c# parallel-processing parallel.foreach

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

await collection.ForEachAsync( m => { m.DoSomething(); } );
Run Code Online (Sandbox Code Playgroud)

VS

Parallel.ForEach( collection, m => { m.DoSomething(); } );
Run Code Online (Sandbox Code Playgroud)

Dar*_*ane 6

它们根本不是“几乎相同”。

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

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

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

至于你的问题

在任何情况下是否有理由选择 Parallel.ForEach 而不是 wait ForEachAsync

答案是肯定的,这样做是有原因的,但为了确定您会使用其中一种场景,您必须了解它们。

这是一个简单的例子:

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

编辑:

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

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

另一方面,如果collection很大和/或是DoSomething()一个流程繁重的任务,那么Parallel.ForEach()肯定是性能最高的选项。


小智 5

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

public class person
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }
Run Code Online (Sandbox Code Playgroud)

这是你的主要课程

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}");
            });
Run Code Online (Sandbox Code Playgroud)

当您运行此代码时,列表项将在差异线程上拆分,并且代码不会按顺序运行,如您在以下输出中看到的那样,我以与原始列表不同的顺序打印 在此输入图像描述

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

在此输入图像描述

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

在此输入图像描述

但是当你运行以下代码时

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}"));
Run Code Online (Sandbox Code Playgroud)

你只会得到一个线程,如此处所示

在此输入图像描述

另外,数据打印将始终按照列表中的相同顺序运行

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