有效使用ASP.NET Web API的async / await
我想在我的Web API项目中使用ASP.NET的async/await
功能。 我不太确定它是否会对我的Web API服务的性能产生影响。 请在下面找到我的应用程序中的工作流程和示例代码。
工作流程:
UI应用程序→Web API端点(控制器)→Web API服务层中的调用方法→调用另一个外部Web服务。 (这里我们有数据库交互等)
控制器:
public async Task<IHttpActionResult> GetCountries()
{
var allCountrys = await CountryDataService.ReturnAllCountries();
if (allCountrys.Success)
{
return Ok(allCountrys.Domain);
}
return InternalServerError();
}
服务层:
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
var response = _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
return Task.FromResult(response);
}
我测试了上述代码并正在工作。 但我不确定是否正确使用async/await
。 请分享你的想法。
我不太确定它是否会对API的性能产生影响。
请记住,服务器端异步代码的主要优点是可伸缩性。 它不会神奇地让你的请求运行得更快。 我在我的关于async
ASP.NET的文章中介绍了几个“我应该使用async
”的注意事项。
我认为你的用例(调用其他API)非常适合异步代码,只要记住“异步”并不意味着“更快”。 最好的方法是首先让你的UI响应和异步; 这会让您的应用程序感觉速度更快,即使速度稍慢。
就代码而言,这不是异步的:
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
var response = _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
return Task.FromResult(response);
}
你需要一个真正的异步执行获得的可扩展性优势async
:
public async Task<BackOfficeResponse<List<Country>>> ReturnAllCountriesAsync()
{
return await _service.ProcessAsync<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
}
或者(如果你在这个方法中的逻辑真的只是一个传递):
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountriesAsync()
{
return _service.ProcessAsync<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
}
请注意,从“内向外”而不是像“外在”这样的工作更容易。 换言之,不要从异步控制器操作开始,然后强制下游方法异步。 相反,请确定自然异步操作(调用外部API,数据库查询等),并使这些异步处于最低级别( Service.ProcessAsync
)。 然后让async
流淌,使您的控制器操作异步作为最后一步。
并且在任何情况下都不应该在这种情况下使用Task.Run
。
这是正确的,但也许没有用。
由于没有什么可以等待的 - 没有阻止可异步操作的API的调用 - 那么您将设置结构来跟踪异步操作(其开销),但不会使用该功能。
例如,如果服务层正在使用支持异步调用的实体框架执行数据库操作:
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
using (db = myDBContext.Get()) {
var list = await db.Countries.Where(condition).ToListAsync();
return list;
}
}
你可以让工作线程在查询数据库时做其他事情(从而能够处理另一个请求)。
等待时间往往是需要一直下降的事情:很难对现有系统进行改造。
您没有有效地利用异步/等待,因为执行同步方法时请求线程会被阻塞ReturnAllCountries()
分配用于处理请求的线程将空闲等待,而ReturnAllCountries()
它是有效的。
如果您可以实现ReturnAllCountries()
以异步,那么您会看到可扩展性的好处。 这是因为线程可能被释放回.NET线程池来处理另一个请求,而ReturnAllCountries()
正在执行。 通过更有效地利用线程,这将使您的服务具有更高的吞吐量。