【问题标题】:How to wait for the result while controller is making parallel call控制器进行并行调用时如何等待结果
【发布时间】:2019-08-27 13:26:33
【问题描述】:

我正在尝试从数据库 (GetAccountDetailAsync) 中查找一组帐户的帐户详细信息,并希望并行运行以使其更快。

[HttpPost]
public async Task<IHttpActionResult> GetAccountsAsync(IEnumerable<int> accountIds)
{

    var resultAccounts = new List<AccountDetail>();

    var task = Task.Run(() =>
    {
        Parallel.ForEach(accountIds, new ParallelOptions
        {
            MaxDegreeOfParallelism = 5 
        }, async accountId =>
        {
            var response = await GetAccountDetailAsync(accountId).ConfigureAwait(false);
            resultAccounts.AddRange(response);

        });
    });

    task.Wait();

    return Ok(resultAccounts);

}

但是,虽然我有任务,但我没有得到结果。等待。 不知道为什么 task.Wait 没有被阻止。

“异步模块或处理程序已完成,而异步操作仍处于挂起状态。”

【问题讨论】:

  • 您确定task.Wait()task 完成执行之前不会阻塞执行吗?
  • 是的,我注意到了
  • 完全删除task(以及Task.RunWait),然后直接调用Parallel.ForEach。并删除Parallel.ForEach 中的async
  • 请注意,您的代码并不安全,因为List 不是线程安全的——而且您似乎是从多个线程调用AddRange。你真的应该使用accountIds.AsParallel().StuffHere().ToList()

标签: c# async-await asp.net-web-api2


【解决方案1】:

Parallel.ForEach 不适用于async 操作,但您可以使用Task.WhenAll 启动所有任务,然后等待它们全部完成:

[HttpPost]
public async Task<IHttpActionResult> GetAccountsAsync(IEnumerable<int> accountIds)
{
    Task<List<AccountDetail>>[] tasks = accountIds.Select(accountId => GetAccountDetailAsync(accountId)).ToArray();
    List<AccountDetail>[] results = await Task.WhenAll(tasks);
    return Ok(results.SelectMany(x => x).ToList());
}

【讨论】:

    【解决方案2】:

    假设您拥有或可以轻松获得没有异步部分的方法GetAccountDetail,这将是最简单的方法:

    [HttpPost]
    public async Task<IHttpActionResult> GetAccountsAsync(IEnumerable<int> accountIds)
    {
       var resultList = accountIds.AsParallel()
                                  .WithDegreeOfParallelism(5)
                                  .Select(GetAccountDetail)
                                  .ToList();
       return Ok(resultList);
    }
    

    【讨论】:

    • “没有异步部分”,你还不如使用Parallel.ForEach而不创建任何任务。
    • @mm8 是的,但是他们需要自己弄清楚并发性并锁定结果容器。
    • 没错,List&lt;AccountDetail&gt; 应该替换为 ConcurrentBag&lt;AccountDetail&gt; 或者您需要同步对它的访问。
    猜你喜欢
    • 2019-10-21
    • 1970-01-01
    • 2015-04-26
    • 2021-06-28
    • 2015-03-25
    • 2022-12-05
    • 2020-09-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多