Parallel.Foreach在幕后做了什么?

时间:2017-12-25 13:00:43

标签: c# .net multithreading foreach parallel-processing

所以我不能理解这里的概念。 我有一个使用Parallel类和Foreach方法的方法。 但我不明白的是,它是否会创建新线程以便更快地运行该功能?

我们以此为例。 我做一个正常的foreach循环。

private static void DoSimpleWork()
        {
            foreach (var item in collection)
            {
                //DoWork();
            }
        }

它将做的是,它将采取列表中的第一项,分配方法DoWork();到它并等到它完成。简单,朴实,有效。

现在..我很好奇有三种情况 如果我这样做。

Parallel.ForEach(stringList, simpleString =>
            {
                DoMagic(simpleString);
            });

将Foreach拆分为4块大块吗? 所以我认为正在发生的是它需要列表中的前4行,将每个字符串分配给每个“线程”(假设并行创建4个虚拟线程)完成工作,然后从该列表中的下一个4开始? 如果这是错的,请纠正我,我真的想了解这是如何工作的。

然后我们有了这个。 基本上是相同但有一个新参数

Parallel.ForEach(stringList, new ParallelOptions() { MaxDegreeOfParallelism = 32 }, simpleString =>
            {
                DoMagic(simpleString);
            });

我很好奇的是这个

new ParallelOptions() { MaxDegreeOfParallelism = 32 }

这是否意味着它将占用该列表中的前32个字符串(如果列表中有许多字符串)然后执行与我上面讨论的相同的事情?

最后一个。

Task.Factory.StartNew(() =>
            {
                Parallel.ForEach(stringList, simpleString =>
                {
                    DoMagic(simpleString);
                });
            });

这会创建一个新任务,将每个“块”分配给它自己的任务吗?

3 个答案:

答案 0 :(得分:2)

不要将异步代码与并行混合。任务是针对异步操作 - 查询数据库,读取文件,等待一些相对计算 - 便宜操作,这样您的用户界面就不会被阻止且无法响应。

平行是不同的。这是为1)多核系统和2)计算 - 密集操作而设计的。我不会详细介绍它是如何工作的,可以在MS文档中找到这种信息。长话短说,平行。很可能会让它自己决定究竟何时以及如何运行。它可能违反你的参数,即MaxDegreeOfParallelism或其他一些。整个想法是提供最佳的并行化,从而尽快完成您的操作。

答案 1 :(得分:2)

Parallel.ForEach执行C#foreach循环的等效操作,但每次迭代并行执行而不是顺序执行。没有排序,它取决于操作系统是否可以找到可用的线程,如果有,它将执行

MaxDegreeOfParallelism 

默认情况下,For和ForEach将使用操作系统提供的线程数,因此从默认值更改MaxDegreeOfParallelism只会限制应用程序将使用多少并发任务。

您通常不需要修改此参数,但可以选择在高级方案中更改它:

  1. 当您知道您正在使用的特定算法无法扩展时 超过一定数量的核心。您可以设置要避免的属性 在其他核心上浪费周期。

  2. 当您同时运行多个算法并且想要 手动定义每个算法可以使用多少系统。

  3. 当线程池的启发式无法确定权限时 要使用的线程数量,最终可能注入太多 线程。例如在长时间运行的循环体迭代中, 线程池可能无法区分 合理的进展或活锁或死锁,可能无法做到 回收为提高性能而添加的线程。您可以设置该属性以确保不使用超过合理数量的线程。

  4. 当您需要对长时间运行的计算绑定任务进行细粒度控制时,通常会使用

    Task.StartNew,就像@СергейБоголюбов提到的那样,不要混淆它们

    它创建一个新任务,该任务将异步创建线程以运行for循环

    您可能会发现此电子书很有用:http://www.albahari.com/threading/#_Introduction

答案 2 :(得分:0)

完成工作,然后从该列表中的下一个4开始?

这取决于您机器的硬件以及机器内核与CPU正在处理的其他进程/应用程序的繁忙程度

这是否意味着它会占用该列表中的前32个字符串(如果列表中有多个字符串),然后执行与我上面讨论的相同的事情?

不,不能保证它会占用前32,可能会更少。每次执行相同的代码时它都会有所不同

Task.Factory.StartNew 会创建一个新任务,但不会像您期望的那样为每个块创建一个新任务。

将Parallel.ForEach放入新任务中将无助于您进一步缩短并行任务本身所需的时间。