任务什么时候真正开始?
public void DoSomething() {
Task myTask = DoSomethingAsync();
Task.WaitAll(new[] { myTask }, 2000);
}
public async Task DoSomethingAsync() {
await SomethingElse();
}
是在
Task myTask = DoSomethingAsync();
中初始化时立即启动还是在Task.WaitAll(new[] { myTask }, 2000);
中说等待时启动?
调用
async
方法会返回一个 hot 任务,即已启动的任务。因此不需要实际的代码来强制它运行。
根据 MSDN(感谢 Stephen Cleary),基于任务的异步模式 (TAP) 模式要求返回的任务是热任务。这意味着除了使用
new Task
创建的任务外,所有任务都将是热门任务。
来自参考文章:
由公共
构造函数创建的任务称为冷任务...所有其他任务都以热状态开始其生命周期。Task
尽管帕特里克·霍夫曼(Patrick Hofman)给出了答案,但我还是想贡献一些例子(特别是通过指向链接文章中的这一部分https://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-模式/基于任务的异步模式-tap?redirectedfrom=MSDN#task-status)。
希望这些例子可以帮助解释。
如果您从执行一些简单的热门任务开始,您会看到它们在初始化后立即启动。
// Using just some HOT task
var first = Task.Delay(2_500);
var second = Task.Delay(2_500);
await Task.Delay(2_500);
Console.WriteLine("Start awaiting HOT tasks");
var stopwatch = Stopwatch.StartNew();
await Task.WhenAll(first, second);
Console.WriteLine(stopwatch.Elapsed);
上面的代码片段将在下面输出,验证任务在初始化和
await Task.WhenAll(…)
之间是否已运行。
Start awaiting HOT tasks
00:00:00.0000866
现在,如果您使用 Task 构造函数,任务将不会启动,而是处于状态
TaskStatus.Created
。我们需要明确启动它们,如下例所示:
// Using Task constructor
var firstNew = new Task(() => Task.Delay(2_500).GetAwaiter().GetResult());
var secondNew = new Task(() => Task.Delay(2_500).GetAwaiter().GetResult());
await Task.Delay(2_500);
Debug.Assert(firstNew.Status == TaskStatus.Created && secondNew.Status == TaskStatus.Created);
firstNew.Start();
secondNew.Start();
Console.WriteLine("Start awaiting NEW tasks");
stopwatch.Restart();
await Task.WhenAll(firstNew, secondNew);
Console.WriteLine(stopwatch.Elapsed);
上面的代码给出了输出:
Start awaiting NEW tasks
00:00:02.5070535
如果您使用
Task.Run
或Task.Factory
,它们将返回已启动的任务。作为示例,此代码:
// Run
var firstRun = Task.Run(async () => await Task.Delay(2_500));
var secondRun = Task.Run(async () => await Task.Delay(2_500));
await Task.Delay(2_500);
Console.WriteLine("Start awaiting RUN tasks");
stopwatch.Restart();
await Task.WhenAll(firstRun, secondRun);
Console.WriteLine(stopwatch.Elapsed);
// Factory
var firstFactory = Task.Factory.StartNew(async () => await Task.Delay(2_500));
var secondFactory = Task.Factory.StartNew(async () => await Task.Delay(2_500));
await Task.Delay(2_500);
Console.WriteLine("Start awaiting FACTORY tasks");
stopwatch.Restart();
await Task.WhenAll(firstFactory, secondFactory);
Console.WriteLine(stopwatch.Elapsed);
输出:
Start awaiting RUN tasks
00:00:00.0002207
Start awaiting FACTORY tasks
00:00:00.0005118