等待Task.Delay()与Task.Delay().等待()

sve*_*and 47 c# asynchronous task wait async-await

在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");
}
Run Code Online (Sandbox Code Playgroud)

第一个示例创建一个打印"开始"的任务,等待5秒打印"完成",然后结束任务.我等待任务完成,然后打印"全部完成".当我运行测试时,它按预期运行.

第二个测试应该具有相同的行为,除了由于使用async和await而在Task内部等待应该是非阻塞的.但是这个测试只是打印"开始"然后立即"完成所有"和"完成"从未打印.

我不知道为什么我会得到这种行为:S非常感谢任何帮助:)

brz*_*brz 47

第二个测试有两个嵌套的任务,你正在等待最外层的任务,修复你必须使用的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");
}
Run Code Online (Sandbox Code Playgroud)

通过调用t.Wait()您正在等待立即返回的最外层任务.


处理这种情况的最终'正确'方法是放弃使用Wait并且只是使用await.将UI附加到异步代码后,Wait可能会导致死锁问题.

    [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");
    }
Run Code Online (Sandbox Code Playgroud)

更好的只是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");
    }
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你工作:)顺便说一下,总是可以使用Task.Run而不是Task.Factory.StartNew或者是否有需要Task.Ract不能处理的Task.Factory.StartNew的情况?:) (3认同)
  • 任务.运行(someAction); 是一个方便的包装器,相当于 Task.Factory.StartNew(someAction, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); (3认同)