【问题标题】:await Task.Delay() vs. Task.Delay().Wait()等待 Task.Delay() 与 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()
  • 在 Main() 方法中不能使用“等待”。您必须使用 Wait() 或旧的 Thread.Sleep()。

标签: c# asynchronous task wait async-await


【解决方案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);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-02
  • 2020-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-12
相关资源
最近更新 更多