在这种情况下避免使用await

时间:2019-11-22 17:01:24

标签: c# async-await

我有一个异步调用,我将其包装在Task中。运行以在另一个线程中运行它。组织分配和所有后续代码是否会一直暂停,直到返回并获得结果?还是会继续,甚至在到达foreach后有时会生成空引用异常?在我的测试中,它从不会抛出错误,但是也许我很幸运。

        IDictionary<string, organization> organizations = Task.Run(() => this.GetOrganizationsAsync()).Result;

...lines of code

        foreach (var organization in organizations)
        {

2 个答案:

答案 0 :(得分:3)

Remarks section of the documentation for Task.Result说:

  

访问属性的get访问器会阻塞调用线程,直到异步操作完成为止;等效于调用Wait方法。

是的,直到GetOrganizationsAsync()完成,它才能继续进行。但是有两件事:

  1. 没有理由使用Task.Run。当您希望某物移动到另一个线程时可以使用它,以便当前线程可以继续执行其他操作。但是,然后您将阻塞当前线程,直到它完成为止。因此Task.Run只是无缘无故地增加了开销。

  2. 阻塞异步操作也会导致死锁问题:Don't Block on Async Code

有什么理由不能仅仅使方法async并使用await GetOrganizationsAsync()?这是更可取的,因为您不会阻塞任何线程。

Microsoft在Asynchronous programming with async and await上有一系列写得很好的文章,值得阅读。

答案 1 :(得分:0)

调用.Result是一个坏主意,因为它有时会导致您的代码被锁定-我建议您做一些阅读以说服自己。

最好的方法是在GetOrganizationsAsync上调用await,并使执行该方法的方法异步。这可能意味着asyc方法开始在整个代码中传播,但这就是cookie崩溃的方式。有很多方法可以避免这样做,而且我已经看到它是在生产代码中编写的,这些代码主要是有效,但是我不建议这样做。

有关此主题的更多阅读内容: Is Task.Result the same as .GetAwaiter.GetResult()?