所以我不能理解这里的概念。 我有一个使用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);
});
});
这会创建一个新任务,将每个“块”分配给它自己的任务吗?
答案 0 :(得分:2)
不要将异步代码与并行混合。任务是针对异步操作 - 查询数据库,读取文件,等待一些相对计算 - 便宜操作,这样您的用户界面就不会被阻止且无法响应。
平行是不同的。这是为1)多核系统和2)计算 - 密集操作而设计的。我不会详细介绍它是如何工作的,可以在MS文档中找到这种信息。长话短说,平行。很可能会让它自己决定究竟何时以及如何运行。它可能违反你的参数,即MaxDegreeOfParallelism或其他一些。整个想法是提供最佳的并行化,从而尽快完成您的操作。
答案 1 :(得分:2)
Parallel.ForEach
执行C#foreach循环的等效操作,但每次迭代并行执行而不是顺序执行。没有排序,它取决于操作系统是否可以找到可用的线程,如果有,它将执行
MaxDegreeOfParallelism
默认情况下,For和ForEach将使用操作系统提供的线程数,因此从默认值更改MaxDegreeOfParallelism只会限制应用程序将使用多少并发任务。
您通常不需要修改此参数,但可以选择在高级方案中更改它:
当您知道您正在使用的特定算法无法扩展时 超过一定数量的核心。您可以设置要避免的属性 在其他核心上浪费周期。
当您同时运行多个算法并且想要 手动定义每个算法可以使用多少系统。
当线程池的启发式无法确定权限时 要使用的线程数量,最终可能注入太多 线程。例如在长时间运行的循环体迭代中, 线程池可能无法区分 合理的进展或活锁或死锁,可能无法做到 回收为提高性能而添加的线程。您可以设置该属性以确保不使用超过合理数量的线程。
Task.StartNew
,就像@СергейБоголюбов提到的那样,不要混淆它们
它创建一个新任务,该任务将异步创建线程以运行for循环
您可能会发现此电子书很有用:http://www.albahari.com/threading/#_Introduction
答案 2 :(得分:0)
完成工作,然后从该列表中的下一个4开始?
这取决于您机器的硬件以及机器内核与CPU正在处理的其他进程/应用程序的繁忙程度
这是否意味着它会占用该列表中的前32个字符串(如果列表中有多个字符串),然后执行与我上面讨论的相同的事情?
不,不能保证它会占用前32,可能会更少。每次执行相同的代码时它都会有所不同
Task.Factory.StartNew 会创建一个新任务,但不会像您期望的那样为每个块创建一个新任务。
将Parallel.ForEach放入新任务中将无助于您进一步缩短并行任务本身所需的时间。