像下面这样的异步方法应该在 ASP.NET MVC 网站中执行而无需等待。
public async Task DoStaff()
{
// business logic here
}
我们找到了两个解决方案来实现这一点,并且都在我们的测试平台上工作:
解决方案 1:
public void DoStaffWrapper()
{
DoStaff();
// clean up
}
public ActionResult Caller()
{
DoStaffWrapper();
// return blah blah blah;
}
解决方案 2:
public async Task DoStaffWrapperAsync()
{
await DoStaff();
// clean up
}
public ActionResult Caller()
{
Task.Run(() => DoStaffWrapperAsync());
// return blah blah blah;
}
那么它们有什么区别呢?哪个更好,为什么?有什么好处吗?
除非您可以精确控制 IIS 池的生命周期(或者除非您实际上没有在 IIS 上运行),否则您应该使用 QueueBackgroundWorkItem
启动您的即发即弃任务。它确保运行时能够跟踪它们,并且不会过早地终止进程。
HostingEnvironment.QueueBackgroundWorkItem(_ => DoStaff());
如果由于某种原因你不想使用这个方法,或者不需要它,那么调用异步方法的两种方式之间有一个重要的区别:
-
DoStaff()
将在当前线程上同步运行,直到 await
找到语句,然后它将放弃对线程的控制(并且您在 DoStaff
之后拥有的任何内容都将能够执行。此外,该方法将在 ASP.NET 的同步上下文中执行,因此如果您无论何时在其中等待调用,我们都不会使用 .ConfigureAwait(false)
。
-
Task.Run(() => DoStaffWrapperAsync())
将完全异步运行,并在单独的上下文中运行(因此您不会遇到上述问题)。
简单来说,采取以下方法:
public Task DoStaff()
{
Thread.Sleep(1000);
await AnotherMethodAsync();
Thread.Sleep(1000);
}
如果您调用 DoStaff
,调用将阻塞一秒钟。如果您调用 Task.Run(() => DoStaff())
,调用将立即返回。但是如果在第一个 await
之前没有大量的工作,那么您将跳到一个新线程而没有任何实际 yield 。