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