Task.WaitAll()的行为是什么?

3
我已经创建了一个任务列表,就像这样:

Task


public void A()
{

}

public void B()
{

}

public void C()
{

}

public void Ex()
{
   Task.WaitAll(Task.Factory.StartNew(A), Task.Factory.StartNew(B), Task.Factory.StartNew(C));
   var p=true;
}

现在我的问题是:列表中的所有任务是否逐一执行,还是并行执行?

p=true

“p”是在所有任务完成之后设置,还是在它们完成之前设置?
2个回答

7

对于第一个问题:

这些任务会按顺序执行还是异步执行。

使用StartNew将在当前TaskScheduler中运行您的任务。默认情况下,它将使用ThreadPool,如果线程池中有任何可用插槽,则将并行运行它。如果任务池中的所有插槽都已占满,则可能会限制任务的执行,以避免CPU被压垮,并且任务可能不会同时执行:没有保证。

这是一个简化的解释,关于调度策略的更完整和详细的解释在TaskScheduler文档中有说明。

另外需要注意的是,StartTask文档提到了StartNew(Action)Run(Action)之间的微妙差别。它们不是完全等价的,与其他答案所述的不同。

从.NET Framework 4.5开始,您可以使用Task.Run(Action)方法快速调用带有默认参数的StartNew(Action)。但是请注意,这两种方法在行为上存在差异:Task.Run(Action)默认情况下不允许使用TaskCreationOptions.AttachedToParent选项启动的子任务附加到当前Task实例,而StartNew(Action)则允许。

对于第二个问题:

"p"是在所有任务完成之后还是在它们完成之前设置的?

简短的答案是是的。

但是,您应该考虑使用另一种方法,因为此方法将阻塞您的线程并无所事事地等待。如果可以,请使用另一种方法将控制权交还给调用者,以便线程被释放并可以由CPU使用。如果运行此代码的线程是ThreadPool的一部分,则尤其如此。

因此,您应该优先使用WhenAll()。它返回一个Task,可以等待它或在其上调用ContinueWith

示例:

var tasks = new Task[] {Task.Factory.StartNew(A), Task.Factory.StartNew(B), Task.Factory.StartNew(C)}; 
await Task.WhenAll(tasks);

没错,是我的疏忽。TaskPool是存在的,但它是响应式扩展的概念。抱歉让你困惑了。 - Fabio Salvalai

2

首先,您正在错误地创建任务。当您实例化一个任务时,您需要调用它的Start方法,否则它将不起作用。

new Task(() => /* Something * /).Start();

如果您按照刚才的方式创建任务(通过调用构造函数并启动或使用TaskFacotry或甚至Task.Run),则默认情况下,线程池线程将专门用于执行该任务,因此该任务将并行执行。

Task.WhenAll方法将阻止调用方法的执行,直到传递给它的所有任务都完成执行为止。

因此,在所有任务完成后,布尔变量将被设置。


1
是的,我刚刚把它改成了 Task.Factory.StartNew(A)。这样可以吗? - sourabh devpura
2
是的,但首选方法是使用Task.Run,它针对大多数基本场景进行了优化。 - SHM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接