使用System.Threading.Tasks.Parallel在线程池中创建新线程?
也许我不理解它…所有Parallel类问题:(
但是从我现在正在阅读的内容中,我了解到当我使用Parallel时,我实际上调动了threadPool中存在的所有线程以执行某些任务/任务。
例如 :
var arrayStrings = new string[1000]; Parallel.ForEach(arrayStrings, someString => { DoSomething(someString); });
因此,在这种情况下,Parallel.ForEach正在调动threadPool中存在的所有线程,用于’DoSomething’任务/任务。
但调用Parallel.ForEach会不会创建任何新线程?
很明显,没有1000个新线程。 但是我们假设有1000个新线程,有些情况下threadPool会释放它所拥有的所有线程,在这种情况下…… Parallel.ForEach会创建任何新线程吗?
简短回答: Parallel.ForEach()
不会“动员所有线程”。 并且在ThreadPool
上调度某些工作的任何操作( Parallel.ForEach()
都可以)导致在池中创建新线程。
简单回答:要正确理解这一点,您需要知道三个抽象级别如何工作: Parallel.ForEach()
, TaskScheduler
和ThreadPool
:
-
Parallel.ForEach()
(和Parallel.For()
)在TaskScheduler
上安排他们的工作。 如果未明确指定调度程序,则将使用当前调度程序。Parallel.ForEach()
在几个Task
之间拆分工作。 每个Task
将处理输入序列的一部分,一旦完成,它将请求另一个部分(如果有的话),依此类推。Parallel.ForEach()
创建了多少个Task
? 尽管TaskScheduler
会让它运行。 这样做的方法是每个Task
在开始执行时首先将其自身的副本排入队列(除非这样做会违反MaxDegreeOfParallelism
,如果你设置它)。 这样,实际并发级别由TaskScheduler
。此外,第一个
Task
实际上将在当前线程上执行,如果TaskScheduler
支持它(这是使用RunSynchronously()
)。 -
默认的
TaskScheduler
只是将每个Task
排入ThreadPool
队列。 (实际上,如果你从另一个Task
启动一个Task
更复杂,但这里没有相关性。)其他TaskScheduler
可以做完全不同的事情,其中一些(如TaskScheduler.FromCurrentSynchronizationContext()
)完全不适合与Parallel.ForEach()
一起使用Parallel.ForEach()
。 -
ThreadPool
使用相当复杂的算法来确定在任何给定时间应该运行多少线程。 但最重要的是调度新工作项可能会导致创建新线程(尽管不一定立即)。 因为使用Parallel.ForEach()
,总会有一些项目排队等待执行,完全取决于ThreadPool
的内部算法来决定线程的数量。
综上所述,几乎不可能确定Parallel.ForEach()
将使用多少线程,因为它依赖于许多变量。 两种极端都是可能的:循环将在当前线程上完全同步运行,并且每个项目将在其自己的新创建的线程上运行。
但一般来说,应该接近最佳效率,你可能不必担心所有这些细节。
Parallel.Foreach不会创建新线程,也不会“动员所有线程”。 它使用来自线程池的有限数量的线程,并将任务提交给它们以进行并行执行。 在当前实现中,默认是每个核心使用一个线程。
我认为你有错误的方法。 从PARALLEL OF PARALLEL PROGRAMMING你可以看到Parallel.ForEach真的是语法糖。
Parallel.ForEach很大程度上归结为这样的事情,
for (int p = 0; p < arrayStrings.Count(); p++) { ThreadPool.QueueUserWorkItem(DoSomething(arrayStrings[p]); }
ThreadPool负责调度。 如果您感兴趣,有一些关于ThreadPool调度程序在某种程度上如何表现的优秀文章,但这与TPL无关。
Parallel根本不处理线程 – 它将TASKS调度到任务框架。 然后有一个调度程序,默认调度程序进入线程池。 这个将尝试找到一个goo数量的线程(4.5比4.0更好)并且Threadpool可能会慢慢启动新线程。
但这不是parallel.foreach的function;)
Parallel.ForEach将创建任何新线程???
它永远不会。 正如我所说 – 它有1000个foreach,然后排队10.000个任务,Point。 任务工厂调度程序将执行它编程要执行的操作((您可以替换它)。通常,默认 – 是的,慢慢地新线程将在原因中出现。