在方法签名中使用async关键字在WebApi端点中返回Task
本文关键字:WebApi 端点 Task 返回 关键字 方法 async | 更新日期: 2023-09-27 18:25:40
如果我想通过返回Task
对象来编写一个非阻塞的web api操作,我可以使用或不使用async
关键字来完成,例如:
使用异步
public async Task<HttpResponseMessage> Get()
{
Func<HttpResponseMessage> slowCall = () =>
{
Thread.Sleep(2000);
return Request.CreateResponse(HttpStatusCode.OK, "Hello world");
};
var task = Task<HttpResponseMessage>.Factory.StartNew(slowCall);
return await task;
}
不使用异步
public Task<HttpResponseMessage> Get()
{
Func<HttpResponseMessage> slowCall = () =>
{
Thread.Sleep(2000);
return Request.CreateResponse(HttpStatusCode.OK, "Hello world");
};
var task = Task<HttpResponseMessage>.Factory.StartNew(slowCall);
return task;
}
它们都能正常工作。然而,我在网上和书中看到的关于编写返回Task
的webapi操作的每个例子都使用async
关键字。当然,我理解这会给你更多的灵活性,因为它可以让你控制你想"等待"什么和不想"等待的"什么。但假设您的功能可以通过任何一种方式得到有效处理,
- 使用一种方法与另一种方法相比有什么优势吗
- 我应该一直使用async关键字吗(如果是,为什么)
- 或者它是无关紧要的
async
关键字允许您通过创建状态机在方法中使用await
。如果您可以在不使用异步任务的情况下管理返回,那么您可以继续并删除它,因为它有一些(非常小的)开销。请记住,它只在少数情况下有用。你的return await
就是其中之一。
另一个区别是如何处理异常。如果在方法的同步部分中存在异常,并且该异常被标记为async
,则该异常将存储在返回的任务中。如果没有关键字,则会定期抛出异常。例如,在这种情况下,有一个很大的区别:
var task = Get(); // unhandled exception without async
try
{
var result = await task; // handled exception with async
}
catch
{
}
我的建议是,即使你不绝对需要*,也要使用async
关键字,因为大多数开发人员都不理解其中的区别,优化中的价值几乎可以忽略不计。
*除非你和你的队友真的知道你在做什么
绕过await
并直接返回Task
有一个优点:性能。您不会分配或处理使用async
方法的状态机。然而,当涉及到例外情况时,会有一些微妙的差异。
在异步示例中,抛出的任何异常都将包含在Task
中。这通常是人们在调用Task返回方法时所认为的情况。在同步示例中,调用时将立即抛出异常。
这也会对异常的堆栈跟踪产生影响。在异步示例中,它将显示Get()
。在同步示例中,它将显示您的匿名委托,或者更糟的是,Task.Factory.StartNew
中的一些内部垃圾,而没有实际引用您的实际代码。这可能会导致调试更加困难。