摘要:在库方法中,何时应该使用async
和await
关键字而不是直接返回Task
?
我相信我的问题与this one有关。但是,这个问题是关于.NET 4.0
和TPL,而我正在使用带有async
和await
关键字的.NET 4.6。所以,我认为我的问题可能得到不同的答案,因为当链接问题得到解答时,这些关键字不存在。
说明:我正在为外部WCF服务编写一个简单的包装器,并且包装器会进行多次SendAsync
调用。现在我认为每个包装器方法应该直接返回Task<>
而不等待。我的理解是async
/ await
应该在应用程序层使用,而不是在库中。
因此,例如,我认为我应该采用每种包装方法的方法:
private Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
return _service.SendAsync(request);
}
但是在互联网上,我找到了使用这种方法的几个帖子:
private async Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
return await _service.SendAsync(request).ConfigureAwait(false);
}
这是另一个我找到on technet的例子:
async Task PutTaskDelay()
{
await Task.Delay(5000);
}
private async void btnTaskDelay_Click(object sender, EventArgs e)
{
await PutTaskDelay();
MessageBox.Show("I am back");
}
那么,我何时应该使用第二种方法(包含async
和await
关键字的方法)?为什么不在不Task
PutTaskDelay
的情况下返回整个async
?我认为我应该尽可能直接返回Task
,并使用async
/ await
仅在应用层中获得最终结果。我对吗?如果没有,我在这里展示的两种方法有什么区别?
我的顾虑:当使用async
和await
关键字时,它似乎只是为编译器提供了额外的工作而没有任何好处。
答案 0 :(得分:8)
我应该在库中使用async await吗?
一切都取决于。如果您打算利用异步编程范例,那么答案是肯定的,大多数时候需要async
和await
个关键字。您很可能会发现自己需要使用async/await
。这是因为在大多数情况下,仅使用Task
和Task<T>
是很困难的,因为您很可能需要推断您调用的异步操作的结果。
此外,根据您的问题,似乎您可能对关键字本身以及它们与Task
和Task<T>
类型的关系有些混淆。请允许我为您澄清一下。
async
关键字允许方法使用await
关键字。最佳做法是让所有异步方法都返回Task
或Task<T>
,除非您无法(例如,如上所示,按钮单击事件处理程序)。 / p>
返回Task
或Task<T>
的方法表示异步操作。当您在图书馆时,建议您始终使用.ConfigureAwait(false)
,原因详见here。另外,我总是将人们指向this detailed article这个主题。
要区分问题中的两种方法:
以下方法返回Task<SignResponse>
。这是一个异步操作,表示要登录的工作。调用者可以等待该方法获取SignResponse
。
private Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
return _service.SignAsync(request);
}
同样,此版本也会执行相同操作... ,但不需要async/await
个关键字。它们不需要的原因是该方法本身不需要使用SignResponse
,因此它可以简单地返回Task<SignResponse>
,如上所示。正如您在问题中指出的那样,当您在不需要时使用async/await
关键字时确实会受到惩罚。这样做会增加一个额外的状态机步骤,因为它等待了结果。
private async Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
return await _service.SignAsync(request).ConfigureAwait(false);
}
最后,如果您需要推断响应,可以使用上述关键字来执行此操作:
private async Task<SignResponse> GetSignDataAsync(SigningRequestType request)
{
var result = await _service.SignAsync(request).ConfigureAwait(false);
if (result.SomeProperty == SomethingWeCareToCheck)
{
_log.Log("Wow, this was un-expected...");
}
return result;
}
答案 1 :(得分:-2)
不要接受我的话,因为我从来没有理解async / await那么好,但最让我困扰的是,所有使用async的方法都必须被标记为async,这让我很烦结束。
我想在一个库中,人们可以选择如何使用这些方法是一件好事,所以你应该使用async,但是我总是发现直接明确地使用Tasks更清楚。