在不等待ASP.NET MVC的情况下启动异步任务的两种方法之间的差异

Vej*_*Vej 1 c# asp.net asp.net-mvc asynchronous async-await

如下所示的异步方法应在ASP.NET MVC网站中等待执行。

public async Task DoStaff()
{
    // business logic here
}
Run Code Online (Sandbox Code Playgroud)

我们找到了两种解决方案来完成此任务,并且都可以在我们的测试平台上工作:

解决方案1

public void DoStaffWrapper()
{
    DoStaff();
    // clean up
}

public ActionResult Caller()
{
    DoStaffWrapper();
    // return blah blah blah;
}
Run Code Online (Sandbox Code Playgroud)

解决方案2

public async Task DoStaffWrapperAsync()
{
    await DoStaff();
    // clean up
}

public ActionResult Caller()
{
    Task.Run(() => DoStaffWrapperAsync());
    // return blah blah blah;    
}
Run Code Online (Sandbox Code Playgroud)

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

Kev*_*sse 5

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

HostingEnvironment.QueueBackgroundWorkItem(_ => DoStaff());
Run Code Online (Sandbox Code Playgroud)

如果出于某种原因您不想使用或不需要此方法,则调用async方法的两种方法之间存在重要区别:

  • DoStaff()将在当前线程上同步运行,直到await找到一条语句为止,然后它将对该线程产生控制权(之后DoStaff执行的任何操作都可以执行。此外,该方法将在ASP.NET的同步上下文中执行,因此您将如果您不使用.ConfigureAwait(false)它来等待内部呼叫,则会遇到麻烦。
  • Task.Run(() => DoStaffWrapperAsync()) 将完全异步运行,并在单独的上下文中运行(因此您不会遇到上述问题)。

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

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

    await AnotherMethodAsync();

    Thread.Sleep(1000);
}
Run Code Online (Sandbox Code Playgroud)

如果您呼叫DoStaff,通话将阻塞一秒钟。如果您呼叫Task.Run(() => DoStaff()),则呼叫将立即返回。但是,如果在第一次学习之前没有大量工作await,那么您将无所适从地跳到新线程。