等待 Task.Delay() 与 Task.Delay().Wait()
Posted
技术标签:
【中文标题】等待 Task.Delay() 与 Task.Delay().Wait()【英文标题】:await Task.Delay() vs. Task.Delay().Wait() 【发布时间】:2015-01-04 02:28:37 【问题描述】:在 C# 中我有以下两个简单的例子:
[Test]
public void TestWait()
var t = Task.Factory.StartNew(() =>
Console.WriteLine("Start");
Task.Delay(5000).Wait();
Console.WriteLine("Done");
);
t.Wait();
Console.WriteLine("All done");
[Test]
public void TestAwait()
var t = Task.Factory.StartNew(async () =>
Console.WriteLine("Start");
await Task.Delay(5000);
Console.WriteLine("Done");
);
t.Wait();
Console.WriteLine("All done");
第一个示例创建一个打印“开始”的任务,等待 5 秒打印“完成”,然后结束该任务。我等待任务完成,然后打印“全部完成”。当我运行测试时,它按预期运行。
第二个测试应该具有相同的行为,只是由于使用了 async 和 await,Task 内部的等待应该是非阻塞的。但是这个测试只打印“开始”,然后立即“全部完成”,永远不会打印“完成”。
我不知道为什么会出现这种行为:S 任何帮助将不胜感激 :)
【问题讨论】:
Task.Delay 是非阻塞的。我看不出你为什么要使用第二个构造。 @RoyDictus 他们都有自己的问题。你永远不应该打电话给Task.Wait()
Waiting for async/await inside a task 的可能重复项
在 Main() 方法中不能使用“等待”。您必须使用 Wait() 或旧的 Thread.Sleep()。
【参考方案1】:
第二个测试有两个嵌套任务,您正在等待最外面的一个,要解决这个问题,您必须使用t.Result.Wait()
。 t.Result
获取内部任务。
第二种方法大致相当于这样:
public void TestAwait()
var t = Task.Factory.StartNew(() =>
Console.WriteLine("Start");
return Task.Factory.StartNew(() =>
Task.Delay(5000).Wait(); Console.WriteLine("Done");
);
);
t.Wait();
Console.WriteLine("All done");
通过调用t.Wait()
,您正在等待立即返回的最外层任务。
处理这种情况的最终“正确”方法是完全放弃使用Wait
,而只使用await
。一旦将 UI 附加到异步代码,Wait
可能会导致 deadlock issues。
[Test]
public async Task TestCorrect() //note the return type of Task. This is required to get the async test 'waitable' by the framework
await Task.Factory.StartNew(async () =>
Console.WriteLine("Start");
await Task.Delay(5000);
Console.WriteLine("Done");
).Unwrap(); //Note the call to Unwrap. This automatically attempts to find the most Inner `Task` in the return type.
Console.WriteLine("All done");
最好使用Task.Run
来启动您的异步操作:
[TestMethod]
public async Task TestCorrect()
await Task.Run(async () => //Task.Run automatically unwraps nested Task types!
Console.WriteLine("Start");
await Task.Delay(5000);
Console.WriteLine("Done");
);
Console.WriteLine("All done");
【讨论】:
感谢工作:) 顺便说一句,使用 Task.Run 而不是 Task.Factory.StartNew 总是可以的,或者在某些情况下我需要 Task.Factory.StartNew 而 Task.Run 不能处理? :) Task.Run(someAction);是一个方便的包装器,等效于 Task.Factory.StartNew(someAction, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);以上是关于等待 Task.Delay() 与 Task.Delay().Wait()的主要内容,如果未能解决你的问题,请参考以下文章
何时使用Task.Delay,何时使用Thread.Sleep?
15.3 Task Task.Yield和Task.Delay说明
REST API 中的 Thread.sleep 与 Task.delay