使用 Await 和 Async 并行运行特定任务

本文关键字:任务 运行 并行 Await Async 使用 | 更新日期: 2023-09-27 18:36:49

因为我试图对需要大量时间才能完成的特定任务进行并行处理。也就是说,ForEach in Linq.请考虑以下代码,

法典

public async Task<List<int>> ReturnRoutAsync(int UserId, int Id)
{
    return await Task.FromResult(db.RoutingListMembers.Where(a => a.RoutingListId == UserId && a.User.UserDeptId == Id).Select(a => a.UserId.Value).ToList());
}
public async Task<List<int?>> CareAllocCount(List<UserWithDeptId> RouteList)
{
    return await Task.FromResult(RouteList.Where(f => f.PoReceiptId == f.PoReceiptId).Select(f => f.UserId).ToList());
}
public async Task<int> UsersCount(int? UserId)
{
    return await Task.FromResult(db.RoutingListMembers.Where(x => x.RoutingListId == UserId).Select(x => x.UserId).Count());
}
public async Task<List<UserWithDeptId>> GetRoutingList(List<UserWithDeptId> RouteList, int Id)
{
    await RouteList.ForEachAsync(async d => { d.RouteUserIdList = await ReturnRoutAsync(d.UserId.Value, Id); d.CareAllocationCnt = await CareAllocCount(RouteList); d.TotRouteUsers = await UsersCount(d.UserId); });
    return RouteList;
}
public async Task<decimal> ReturnAmount(int Id, int Year)
{
    .... (Some other Logic) ....
    var RouteList = Model.Where(asd => asd.Year == Year).ToList();
    RouteList = await GetRoutingList(RouteList, Id);
    .... (Other logic here)....
    var Amount = NewModelList.Sum(asd => asd.Allocated_Cost_to_Dept); // returns decimal
    return Amount;
}
[GridAction]
public ActionResult _Index(int Year, int? page)
{
      var model = (from Dept in db.UserDepts
                     select new ReviewHead
                     {
                         Header = Dept.Description,
                         DeptId = Dept.Id,
                     }).ToList();
        List<ReviewHead> NewList = new List<ReviewHead>();
        foreach (var temp in model)
        {
            ReviewHead RH = new ReviewHead();
            RH.Amount = ReturnAmount(temp.DeptId, Year); // I am getting the compiler error saying that it cannot convert Task<decimal> to decimal.
            RH.DeptId = temp.DeptId;
            RH.Header = temp.Header;
            NewList.Add(RH);
        }
        return View(new GridModel(NewList));
}
public static async Task ForEachAsync<T>(this List<T> list, Func<T, Task> func)
{
    foreach (var value in list)
    {
        await func(value);
    }
}

当我将上面的一个更改为使用类似以下代码Task<ActionResult>时,我收到服务器错误,因为该过程无法"异步"进行。任何帮助将不胜感激。

更新 - 我确实更改了操作结果方法,如下所示

[GridAction]
public async Task<ActionResult> _Index(int Year, int? page)
{
      var model = (from Dept in db.UserDepts
                     select new ReviewHead
                     {
                         Header = Dept.Description,
                         DeptId = Dept.Id,
                     }).ToList();
        List<ReviewHead> NewList = new List<ReviewHead>();
        foreach (var temp in model)
        {
            ReviewHead RH = new ReviewHead();
            RH.Amount = await ReturnAmount(temp.DeptId, Year);
            RH.DeptId = temp.DeptId;
            RH.Header = temp.Header;
            NewList.Add(RH);
        }
        return View(new GridModel(NewList));
}

运行时错误

System.InvalidOperationException was unhandled by user code
HResult=-2146233079
Message=The asynchronous action method '_Index' returns a Task, which cannot be executed synchronously.
Source=System.Web.Mvc
StackTrace:
   at   System.Web.Mvc.Async.TaskAsyncActionDescriptor.Execute(ControllerContext   controllerContext, IDictionary`2 parameters)
   at  System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
   at System.Web.Mvc.Controller.ExecuteCore()
   at Vibrant.Controllers.BaseController.ExecuteCore() in e:'Vibrant3_SVN_Latest'Vibrant'Vibrant'Controllers'BaseController.cs:line 42
   at System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext)
   at System.Web.Mvc.Controller.<>c__DisplayClass19.<BeginExecute>b__13()
   at System.Web.Mvc.Async.AsyncResultWrapper.<.cctor>b__0(IAsyncResult asyncResult, Action action)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
   at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
   at System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag)
   at System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult)
   at System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult)
   at System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
   at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
   at System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag)
   at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
   at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
InnerException: 

使用 Await 和 Async 并行运行特定任务

查看异常:

异步操作方法"_Index"返回一个无法同步执行的任务。

听起来有些东西无法处理异步代码。正常的MVC操作可以正常工作async,所以它一定是别的东西。喜欢这个:

Vibrant.Controllers.BaseController.ExecuteCore() in e:''Vibrant3_SVN_Latest''Vibrant''Vibrant''Controllers''BaseControllers.cs:line 42

听起来像"充满活力的" - 不管是什么 - 需要更新以启用异步请求。

同时,您必须使代码同步。这并不太难,因为代码实际上已经同步了。

特别是,此方法:

public async Task<List<int>> ReturnRoutAsync(int UserId, int Id)
{
  return await Task.FromResult(db.RoutingListMembers.Where(a => a.RoutingListId == UserId && a.User.UserDeptId == Id).Select(a => a.UserId.Value).ToList());
}

有一个不必要的async/await,它只是解开一个任务,然后将结果包装回一个任务中,所以可以删除这些:

public Task<List<int>> ReturnRoutAsync(int UserId, int Id)
{
  return Task.FromResult(db.RoutingListMembers.Where(a => a.RoutingListId == UserId && a.User.UserDeptId == Id).Select(a => a.UserId.Value).ToList());
}

此外,Task.FromResult同步操作。这个方法根本没有异步,所以我们可以让它同步。由于无论如何它都是同步的,因此同步表示更自然:

public List<int> ReturnRout(int UserId, int Id)
{
  return db.RoutingListMembers.Where(a => a.RoutingListId == UserId && a.User.UserDeptId == Id).Select(a => a.UserId.Value).ToList();
}

对方法执行此操作后,您的逻辑只是:

public decimal ReturnAmount(int Id, int Year)
{
  .... (Some other Logic) ....
  var RouteList = Model.Where(asd => asd.Year == Year).ToList();
  RouteList = GetRoutingList(RouteList, Id);
  .... (Other logic here)....
  var Amount = NewModelList.Sum(asd => asd.Allocated_Cost_to_Dept); // returns decimal
  return Amount;
}

_Index与您的第一个示例相同。