等待Task.Result会如何影响嵌套的异步/等待方法?

5
这个有点啰嗦,但我来试一下翻译....
假设我有以下接口:

Given that I have an interface like so:

public interface IWebClientHelper
{
    TPayload Get<TPayload>(string url);
}

这里的Get方法会调用提供的URL,返回一个包含类型为TPayload的Json对象的响应。然后将该Json反序列化为TPayload并返回。

我希望将Get方法的实现异步化(或更具体地说,将Get方法中包含的HTTP调用异步化),但据我所知,这需要改变Get方法的签名:

Task<TPayload> Get<TPayload>(string url);

我希望保持界面原样,因此我创建了第二个界面:
public interface IAsyncWebClientHelper
{
    Task<TPayload> Get<TPayload>(string url);
}

我将那部分内容注入到我的IWebClientHelper实现中。现在,我的IWebClientHelper实现看起来像这样:
public TPayload Get<TPayload>(string url)
{
    return _asyncWebClientHelper.Get<TPayload>(url).Result;
}

_asyncWebClientHelperGet方法包含以下代码行:

message = await httpClient.GetAsync(url);

我不太清楚的是:我是否正确地认为这行代码 return _asyncWebClientHelper.Get<TPayload>(url).Result 会阻塞执行直到该方法返回?还是该方法内部的 await 关键字会释放线程,直到它从 url 接收到响应?


2
这是同步-异步,这是一种反模式。 - usr
1个回答

19

是的,使用Result意味着您的方法将会阻塞。然而,这很可能导致死锁。您没有告诉我们太多关于上下文的信息,但如果您在一个需要在await之后返回到同一线程的上下文中,但由于Result而被阻塞,那么您基本上会死锁。您需要非常小心地使用任何阻塞调用,比如Result属性或Wait()方法。

从根本上讲,试图在不使您的接口异步化的情况下使用异步性是棘手/无意义的。您最好全面地采用异步性,或者坚持使用同步版本。毕竟,如果您要保持线程阻塞直到异步任务完成,那么异步性的好处是什么?


我认为这可能是情况,只是想在我开始替换所有64个同步接口的引用之前确认一下。 - Chris Payne
1
@paynecrl97:我很同情你。将代码从同步转换为异步永远不是一件有趣的事情。 - Jon Skeet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接