在调用 Wait 之前访问任务的结果实际上会做什么?

Mr.*_*Boy 0 c# task-parallel-library

var task = Task.Run(() => DoSomeStuff()).Result;

这里到底发生了什么?

我做了一个小测试:

using System;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {
        var r = Task.Run( () => {Thread.Sleep(5000); return 123; }).Result;
        Console.WriteLine(r);
    }
}
Run Code Online (Sandbox Code Playgroud)

5 秒后打印“123”。那么访问任何此类属性是否可以Task作为调用 ie 的快捷方式,Task.Wait()这样做安全吗?


以前我的代码调用后Task.Delay(5000)立即返回“123”。我在我的问题中修复了这个问题,但将其留在这里作为评论和答案引用它。

Eri*_*ert 6

你问了两个问题。首先,Result隐式访问是否会导致同步Wait?是的。但更重要的问题是:

这样做安全吗?

这样做并不安全。

很容易陷入这样的情况:您正在同步等待的任务已安排工作在将来运行,然后才完成到您刚刚置于睡眠状态的线程上。现在我们遇到的情况是,线程在睡眠线程完成一些工作之前不会醒来,但它永远不会这样做,因为它处于睡眠状态

如果您已经知道任务已完成,那么可以安全地同步等待结果。如果不这样做,那么同步等待是不安全的。

现在,您可能会说,假设我通过其他方式知道同步等待未完成的任务是安全的。那么等待安全吗?好吧,根据问题的假设,是的,但等待仍然可能不明智请记住,异步的重点是在高延迟的世界中有效地管理资源。如果您同步等待异步任务完成,那么您将强制一个工作线程休眠,直到另一个工作线程完成;睡觉的工人可能正在工作!异步的全部目的是避免工人闲置的情况,所以不要强迫他们这样做。

Anawait异步等待。这是一个等待,意味着“等待运行当前工作流程的其余部分,直到该任务完成后,但在等待期间找到一些事情要做”。我们做了很多工作将其添加到语言中,所以使用它吧!

  • @Mr.Boy 如果您对旧式延续(`ContinueWith`)感到满意并且对异步/等待魔术感到不舒服,那么无论如何您可以继续使用旧的东西。他们仍然像以前一样工作。只是避免将它们与新东西混合。将经典的 TPL 技术与 async/await 相结合会带来挫败感和问题。 (2认同)