好的,所以,第二个是简单的,所以让我们处理那个。
对于第二个任务 ,t2您不会对 的结果做任何事情Task.Delay(1000)。你不这样做await,你不这样做Wait,等等。鉴于该方法不是async我认为你的意思是它是一个阻塞等待。为此,您需要添加Wait()到Delay调用的末尾以使其成为阻塞等待,或者只使用Thread.Sleep().
对于第一个任务,你被你正在使用的事实所困扰var。不使用时会发生什么更清楚var:
Task<Task<int>> t1 = Task.Factory.StartNew(async () =>
{
await Task.Delay(2000);
return 2;
});
您正在返回一个 task of 的任务int,而不仅仅是一个Taskof int。一旦内部任务完成启动,外部任务就“完成”了。当您使用时,WhenAll您不关心外部任务何时完成,您关心的是内部任务何时完成。有很多方法可以处理这个问题。一是使用Unwrap。
Task<int> t1 = Task.Factory.StartNew(async () =>
{
await Task.Delay(2000);
return 2;
}).Unwrap();
现在您已经达到了预期Task<int>,并且WhenAll将至少花费 2000 毫秒,正如预期的那样。您还可以添加另一个await调用来做同样的事情:
Task<int> t1 = await Task.Factory.StartNew(async () =>
{
await Task.Delay(2000);
return 2;
});
正如 svick在评论中提到的那样,另一种选择是只使用Task.Run而不是StartNew. 对于接受 a并返回 a并自动为您解包它们的Task.Run方法有一组特殊的重载:Func<Task<T>>Task<T>
Task<int> t1 = Task.Run(async () =>
{
await Task.Delay(2000);
return 2;
});
出于这个原因,Task.Run当您创建异步 lambda 时,最好将其用作默认选项,因为它会为您“处理”此问题,尽管对于您无法使用的复杂情况,最好注意它Task.Run。
最后我们来到了你没有做的选项,这就是你在这种情况下可能应该实际做的事情。由于Task.Delay已经返回了一个任务,所以没有必要把它StartNew放在首位。而不是创建一个嵌套任务并使用Unwrap你不能首先包装它:
var t3 = Task.Delay(3000);
await Task.WhenAll(t1, t2, t3);
如果您实际上只想等待固定的时间,那您应该这样做。