在ASP.NET MVC中无需等待即可启动异步任务的两种方法之间的区别

时间:2017-06-07 04:57:20

标签: c# asp.net asp.net-mvc asynchronous async-await

应该在不等待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;    
}

那么他们之间有什么区别?哪个更好,为什么?有什么好处吗?

1 个答案:

答案 0 :(得分:4)

除非您能够精确控制IIS池的生命周期(或者除非您实际上并未在IIS上运行),否则应使用QueueBackgroundWorkItem启动即发即弃任务。它确保运行时能够跟踪它们,并且不会过早终止该过程。

HostingEnvironment.QueueBackgroundWorkItem(_ => DoStaff());

如果出于某种原因你不想使用这种方法,或者不需要它,那么调用异步方法的两种方法之间有一个重要的区别:

  • DoStaff()将在当前线程上同步运行,直到找到await语句,然后它将控制线程(以及DoStaff之后能够执行的任何内容此外,mehtod将在ASP.NET的同步上下文中执行,因此如果您在等待内部调用时未使用.ConfigureAwait(false),则会遇到麻烦。
  • Task.Run(() => DoStaffWrapperAsync())将完全异步运行,并且在单独的上下文中(因此您不会遇到上述问题)。

简单来说,请采用以下方法:

public Task DoStaff()
{
    Thread.Sleep(1000);

    await AnotherMethodAsync();

    Thread.Sleep(1000);
}

如果您拨打DoStaff,则通话将被阻止一秒钟。如果您拨打Task.Run(() => DoStaff()),呼叫将立即返回。但是如果在第一个await之前没有大量的工作,那么你将跳到一个新的线程,没有实际的收获。