从here等来源读取TPL中的内联后,我得到的印象是对Task.Wait()的调用将启动尚未开始的任务(至少使用默认调度程序) )。但是,写一个快速演示,如:
var taskB = new Task(
() =>
{
Console.WriteLine("In TaskB");
System.Threading.Thread.Sleep(5000);
Console.WriteLine("Leaving TaskB");
});
var taskA = new Task(
() =>
{
Console.WriteLine("In TaskA");
System.Threading.Thread.Sleep(500);
Console.WriteLine("Waiting on TaskB");
taskB.Wait();
Console.WriteLine("Leaving TaskA");
});
taskA.Start();
taskA.Wait();
导致死锁。 TaskA进入taskB.Wait()行,但taskB永远不会启动。我没有搞乱调度程序或任何东西,所以我不确定为什么对taskB的.Wait()调用不会导致它启动。
答案 0 :(得分:15)
Wait()
不会导致任务Start()
。如果在未启动的任务上调用Wait()
,它将等待它开始并完成,直到完成,等待超时或等待被取消。由于您对Wait()
的调用不包含取消令牌或超时,因此完成任务无限。
我认为你在博客中有什么令人困惑的是这一行:
但是,如果它还没有开始执行,Wait可能会拉动 将任务排除在排队并执行的调度程序之外 它内联在当前线程上。
这里的关键是“尚未开始执行”。这并不意味着Start()
未被调用,而是Start()
被调用,它调度任务并使其准备好执行,但任务尚未开始执行。
Start()
是安排执行任务所必需的,它不会立即开始执行。这是那个模糊的主要观点。如果任务已准备好但尚未安排,则可以内联。但它不会启动甚至没有安排的任务。
如果您查看MSDN(See here)中的TaskStatus
,您会看到以下值:
创建任务(使用new或factory)时,它处于Created
状态。在这种状态下任务没有任何变化。一旦它开始,然后它移动到WaitingForActivation
,依此类推,直到它到达Running
,根据该博客可以内联它是可能的。
所以,长话短说,创建任务只是将其置于Created
状态,如果调用Wait()
则不会启动它。有意义吗?
答案 1 :(得分:2)
该文章中提到的内联与任务开始不同。等待任务不会启动它 - 这可以很容易地证明。试试以下内容:
namespace Test
{
using System;
using System.Threading.Tasks;
internal class TestCompile
{
private static void Main(string[] args)
{
Task t = new Task(() => Console.WriteLine("Executed!"));
t.Wait(5000);
Console.WriteLine("After wait...");
Console.ReadKey();
}
}
}
你会发现任务永远不会开始......
对task.Wait()
的调用无法启动任务。如果出现以下情况,它将导致Task立即执行并在当前线程(使用默认调度程序)上“内联”:
第三点是模糊 - 它可以在不同的调度程序上内联执行,但这需要其他调度程序能够立即执行它,因此它依赖于调度程序是支持它的调度程序。