如何以顺序方式执行异步函数的动态列表?

How to execute a dynamic list of async functions in a sequential way?

我重构了一个 Web API 以依赖于 ASP.NET 核心 3.1 中的 async/await,并且我有以下场景:统计方法按顺序计算指标列表,这些指标是在列表中定义。

readonly Dictionary<StatisticItemEnum, Func<Task<SimpleStatisticItemApiModel>>> simpleItemActionMap =
    new Dictionary<StatisticItemEnum, Func<Task<SimpleStatisticItemApiModel>>>();

private void InitSimpleStatisticFunctionsMap()
{
    simpleItemActionMap.Add(StatisticItemEnum.AllQuestionCount, GetAllQuestionCountApiModel);
    simpleItemActionMap.Add(StatisticItemEnum.AllAnswerCount, GetAllAnswerCountApiModel);
    simpleItemActionMap.Add(StatisticItemEnum.AverageAnswer, GetAverageAnswer);
    // other mappings here
}

private async Task<SimpleStatisticItemApiModel> GetAllQuestionCountApiModel()
{
    // await for database operation
}

private async Task<SimpleStatisticItemApiModel> GetAllAnswerCountApiModel()
{
    // await for database operation
}

private async Task<SimpleStatisticItemApiModel> GetAverageAnswer()
{
    // await for database operation
}

代码按顺序遍历每个项目并计算它,重构后它看起来像这样:

itemIds.ForEach(itemId =>
{
    var itemEnumValue = (StatisticItemEnum) itemId;
    if (simpleItemActionMap.ContainsKey(itemEnumValue))
    {
        var result = simpleItemActionMap[itemEnumValue]().Result;
        payload.SimpleStatisticItemModels.Add(result);
    }
}); 

我知道 Task.Result might lead to deadlocks,但我找不到任何其他方法来完成这项工作。

问题:如何按顺序执行异步函数的动态列表?

我认为你可以这样做:

itemIds.ForEach(async itemId =>
{
    var itemEnumValue = (StatisticItemEnum) itemId;
    if (simpleItemActionMap.ContainsKey(itemEnumValue))
    {
        var result = await simpleItemActionMap[itemEnumValue]();
        payload.SimpleStatisticItemModels.Add(result);
    }
}); 

您应该将 ForEach 调用更改为常规 foreach,然后您可以使用 await:

foreach (var itemId in itemIds)
{
  var itemEnumValue = (StatisticItemEnum) itemId;
  if (simpleItemActionMap.ContainsKey(itemEnumValue))
  {
    var result = await simpleItemActionMap[itemEnumValue]();
    payload.SimpleStatisticItemModels.Add(result);
  }
}

不要使 ForEach lambda async;这将导致 async void 方法,您应该 avoid async void.