如果我们同步等待结果,是否有使用任务的好处?

时间:2014-03-20 20:57:04

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

我有一个部分操作,需要调用从数据库调用返回任务的异步方法。由于我无法进行异步部分操作,因此我需要等待任务完成:

public ActionResult TopMenu()
{
  var topMenuTask = Task.Run<IEnumerable<TopMenuItem>>( () => 
    { return _menuService.GetTopMenu(); });
  topMenuTask.Wait();

  //view model population code goes here

  return PartialView(viewModel);
}

我的理解是,执行异步DB(IO)调用的好处是我们将线程重新排列到线程池,以便在IO完成时它可以提供更多请求,但这不是一个moo在这种情况下,我们正在同步等待它?

4 个答案:

答案 0 :(得分:4)

我从您的问题描述中假设GetTopMenu返回Task,因此should actually be called GetTopMenuAsync

在这种情况下,您最好的选择可能就是您正在做的事情:

public ActionResult TopMenu()
{
  var topMenuTask = Task.Run(() => _menuService.GetTopMenuAsync());
  var topMenu = topMenuTask.Result;

  //view model population code goes here

  return PartialView(viewModel);
}
  

我的理解是,执行异步DB(IO)调用的好处是我们将线程重新排列到线程池,以便它可以在IO完成时提供更多请求,但这不是一个moo点。这种情况,因为我们正在同步等待它?

正确。通过将(异步)数据库访问包装在(同步)部分操作中,代码会使async的好处无效。

这是平台的限制(ASP.NET MVC)。请投票on the issueon uservoice

答案 1 :(得分:3)

您将从将执行该逻辑的线程池中召唤一个线程,但将阻止Web请求线程等待结果。所以不,没有任何好处。

为什么你不能这样做?:

public async Task<ActionResult> TopMenu()
{
    var topMenu = await Task.Run<IEnumerable<TopMenuItem>>( () => { return _menuService.GetTopMenu(); });

    //view model population code goes here

    return PartialView(viewModel);
}

另一种选择是使用经典的异步MVC方式,但您必须从AsyncController而不是Controller派生您的控制器:

  public void TopMenuAsync()
  {
      AsyncManager.OutstandingOperations.Increment();
      Task.Run<IEnumerable<TopMenuItem>>(() => { return _menuService.GetTopMenu(); })
          .ContinueWith(t =>
          {
              AsyncManager.Parameters["topMenu"] = t.Result;
              AsyncManager.OutstandingOperations.Decrement();
          });
  }

  public ActionResult TopMenuCompleted(TopMenuItem topMenu)
  {
      //view model population code goes here

      return PartialView(viewModel);
  }

答案 2 :(得分:3)

您不应该在ASP.NET中使用Task.Run。您仍受限于单个HTTP请求/响应时间范围,它不会加快内容交付速度,只会引入额外的线程切换,请检查this

所以,你的行动应该是这样的:

public ActionResult TopMenu()
{
  var topMenu = return _menuService.GetTopMenu();

  //view model population code goes here

  return PartialView(viewModel);
}

如果部分视图可能需要一段时间才能渲染,请考虑使用以下技术:

http://blog.michaelckennedy.net/2012/11/13/improve-perceived-performance-of-asp-net-mvc-websites-with-async-partialviews/

答案 3 :(得分:1)

你是正确的..这通常是你推迟使用Task决定调用者,或提供调用的异步和非异步版本的原因(例如:{{1}和GetTopMenu)。如果强制使用异步调用,那么就会遇到这样的情况。

您可以选择加载视图并通过AJAX异步拨打电话。您还可以在此方案中为用户提供可视反馈。在此方案中使用GetTopMenuAsync将释放IIS的工作进程以继续提供请求。