Await 和 .Result 永远等待

时间:2021-07-11 03:05:09

标签: c# asynchronous async-await

为什么下面的程序永远不会结束?

namespace Example
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var result = await  new Program().test();
            Console.WriteLine(result);
        }

        private async Task<(int, string)> test()
        {
            var result =  new Task<(int, string)>(() => (10, "sssss"));
            return (result.Result.Item1, result.Result.Item2);
        }
    }
}

我注意到的是,result.Result 或写 await new Task<(int, string)>(() => (10, "sssss")); 会让程序永远等待!!

2 个答案:

答案 0 :(得分:4)

Task 构造函数创建一个“冷”任务,一个尚未启动的任务。如果您 await 这样的任务,await 将永远不会完成,因为该任务将永远处于 Created 状态,并且永远不会转换到 RanToCompletion 状态。要启动冷创建的任务,您必须调用其 StartRunSynchronously 方法,最好将 TaskScheduler.Default 作为参数传递:

private Task<(int, string)> TestAsync()
{
    var task = new Task<(int, string)>(() => (10, "sssss"));
    task.Start(TaskScheduler.Default);
    return task;
}

使用 Task 构造函数创建冷任务是一种在实践中很少使用的高级技术。创建 delegate-based tasks 的常用方法是使用静态 Task.Run 方法,该方法创建热点任务。下面的方法在功能上与之前的方法相同¹:

private Task<(int, string)> TestAsync()
{
    return Task.Run(() => (10, "sssss"));
}

请注意,以上两种方法都被认为是不好的做法,原因解释了here

¹ 实际上并不完全相同。第二个示例启动具有 TaskCreationOptions.DenyChildAttach 配置的任务。可以在 here 中找到有关这方面的更多信息。

答案 1 :(得分:3)

混合使用 async await 和阻塞调用如 .Result 会导致死锁

如果没有异步,则无需等待。只需用您想要的值返回 Task.FromResult

private Task<(int, string)> test() {
    (int, string) value =  (10, "sssss");
    return Task.FromResult(value);
}

它将返回一个成功完成的具有指定结果的任务。