在方法签名中使用async关键字在Web Api端点中返回Task

如果我想通过返回一个Task对象来编写一个非阻塞的web api动作,我可以使用或不使用async关键字这样做:

使用异步

 public async Task Get() { Func slowCall = () => { Thread.Sleep(2000); return Request.CreateResponse(HttpStatusCode.OK, "Hello world"); }; var task = Task.Factory.StartNew(slowCall); return await task; } 

不使用异步

 public Task Get() { Func slowCall = () => { Thread.Sleep(2000); return Request.CreateResponse(HttpStatusCode.OK, "Hello world"); }; var task = Task.Factory.StartNew(slowCall); return task; } 

他们都正常工作。 但是,我在编写返回Task的web api操作时看到的每个例子(在线和书籍)都使用async关键字。 当然,我明白这会给你更大的灵活性,因为它可以让你控制你想要“等待”的东西,什么不是。 但假设您的function可以有效地处理,

  • 使用一种方法与另一种方法有什么优势吗?
  • 我应该总是使用async关键字(如果是这样,为什么)?
  • 或者它无关紧要?

async关键字允许您通过创建状态机在方法中使用await 。 如果您可以管理返回异步任务而不使用它,您可以继续删除它,因为它有一些(非常小的)开销。 请记住,它仅在少数情况下有用。 您的return await是其中之一。

另一个区别是如何处理exception。 如果方法的同步部分中存在exception并且将其标记为async则exception将存储在返回的任务中。 如果没有关键字,则会定期抛出exception。 例如,在这种情况下,有一个很大的区别:

 var task = Get(); // unhandled exception without async try { var result = await task; // handled exception with async } catch { } 

我的建议是使用async关键字,即使你不是绝对需要*,因为大多数开发人员不理解差异,优化中的值几乎可以忽略不计。


*除非你和你的队友真的知道你在做什么。

绕过await并直接返回Task有一个好处:性能。 您不会分配或处理使用async方法的状态机。 但是,当涉及例外时,存在一些细微差别。

在异步示例中,抛出的任何exception都将包含在Task 。 这通常是人们在调用任务返回方法时会发生的事情。 在同步示例中,将在调用时立即抛出exception。

这也会对exception的堆栈跟踪产生影响。 在异步示例中,它将显示Get() 。 在同步示例中,它将显示您的匿名委托或更糟糕的是, Task.Factory.StartNew一些内部废话,没有实际引用您的实际代码。 这可能导致调试更加困难。