我已经想了一段时间了,所有UserStore
方法都返回Task
或类型化Task<T>
,但是为什么呢?为什么不直接返回 T? 我知道它们是 Aync 方法并且是 OWIN 中间件的一部分,这与它有关吗?
我还注意到,一些返回普通旧Task
的方法实际上返回了一个空Task
。 asp.net 网站的示例返回Task.FromResult<object>(null)
http://www.asp.net/identity/overview/extensibility/overview-of-custom-storage-providers-for-aspnet-identity。 我也看过Task.FromResult(0)
,如果我返回一个带有Action
的任务:
return new Task(() =>
{
context.User.Add(new User); context.SaveChanges()
})
然后,不会调用Task
内的Action
。为什么会这样,返回空Task
有什么意义?在我看来,返回Task
类似于void
方法,对吗?
首先,我真的建议您阅读MSDN/使用异步和Await进行异步编程,这对于了解所有异步/等待的工作原理(幕后)非常有帮助。
实际使用这些技术的原因是UserManager实现通常意味着对数据库工作,这在计算机时间中是"慢的"(Jeff Atwood关于该主题的精彩阅读:http://blog.codinghorror.com/the-infinite-space-between-words/)。
出于这个原因,UserManager方法为您提供了将来为您提供TypeX
或ResultY
的承诺,但这需要时间。为了在应用程序等待数据库应答时释放资源(例如),将等待线程置于睡眠状态返回到 ThreadPool,并且释放的容量可用于另一个传入请求(或在此期间可能异步完成的任何任务)。
编辑:谢谢希伯特@Neil
根据 MSDN/异步编程文档:
异步对于可能阻塞的活动至关重要, 例如,当您的应用程序访问 Web 时。访问网络 资源有时会变慢或延迟。如果此类活动被阻止 在同步进程中,整个应用程序必须等待。在一个 异步进程,应用程序可以继续其他工作 这不依赖于 Web 资源,直到潜在的阻塞 任务完成。
数据库调用(特别是在 Microsoft Azure 等云环境中)会阻止 I/O 进程,因此 ASP.NET 标识系统中的大多数 API 都是异步的。
为什么空Task
?返回空Task
是Async/Await Programming
模型中的最佳实践。异步方法有三种可能的返回类型:Task
、Task<T>
;和void
,但异步方法的自然返回类型只是Task
和Task<T>
。从同步代码转换为异步代码时,任何返回类型T
的方法都将成为返回Task<T>
的异步方法,任何返回void
的方法都将成为返回Task
的异步方法。
- 异步 void 方法具有不同的错误处理语义。当一个 异常从异步任务或异步任务
方法中抛出, 捕获该异常并将其放置在 Task 对象上。使用异步 void 方法,没有 Task 对象,因此抛出任何异常 的异步 void 方法将直接在 同步异步 void 方法时处于活动状态的上下文 开始。 - 异步 void 方法具有不同的组合语义。异步方法 返回任务或任务
可以使用 await 轻松撰写, Task.WhenAny、Task.WhenAll 等。返回 void 的异步方法 不要提供一种简单的方法来通知调用代码他们有 完成。启动几个异步 void 方法很容易,但它是 不容易确定他们什么时候完成。异步无效方法将 在开始和完成时通知他们的同步上下文,但 自定义同步上下文是一个复杂的常规解决方案 应用程序代码。 - 异步无效方法很难测试。因为差异 在错误处理和撰写中,很难编写单元测试 调用异步 void 方法。MSTest 异步测试支持 仅适用于返回任务或任务
的异步方法。有可能 以安装同步上下文,以检测何时所有异步无效 方法已完成并收集任何异常,但很多 更容易让异步 void 方法返回任务。
您应该更喜欢async Task
而不是async void
。Async Task
方法使错误处理、可组合性和可测试性更加容易。有关更多信息,请阅读本文:异步编程的最佳实践