【问题标题】:Populate dictionary asynchronously异步填充字典
【发布时间】:2020-05-12 17:33:23
【问题描述】:

我有一个简单的foreach 循环(如下所示),它遍历集合并进行异步 API 调用以根据当前迭代器值获取数据。

foreach (var group in groups)
{
    var usersInGroup = await this.tableauService.GetUsersInTableauGroup(group.Id);

    // do work with `usersInGroup`
}

我不想每次迭代都调用 API,而是想为每个 API 调用创建一个异步任务并同时执行它们,结果填充一个由group.Id 键入的字典。这可能吗?

在我的脑海中,代码看起来像:

IList<Task<string[]>> tasks = new List<Task<string[]>>();
IDictionary<string, string[]> dictionary = new Dictionary<string, string[]>();

foreach (var group in groups)
{
    tasks.Add(this.tableauService.GetUsersInTableauGroup(group.Id));
    // Somehow define callback of each task to hydrate dictionary
}

await Task.WhenAll(tasks);

【问题讨论】:

    标签: c# .net asp.net-core .net-core


    【解决方案1】:

    Task.WhenAll() 返回任务的所有值,所以你可以这样做:

    var tasks = groups
      .Select(async g => new 
      {
        g.Id, 
        Values = await this.tableauService.GetUsersInTableauGroup(g.Id)
      });
    var results = await Task.WhenAll(tasks);
    var dictionary = results
      .ToDictionary(r => r.Id, r => r.Values);
    

    【讨论】:

    • @SoheilAlizadeh:不,这会产生Task&lt;{anonymous}&gt;-返回Func&lt;&gt;。 (否则,Task.WhenAll() 将如何等待这些任务并获得它们的结果?)
    • @SoheilAlizadeh 它没有返回 void,它是 Func&lt;T,TResult&gt;
    • @StriplingWarrior 似乎是不错的解决方案,我无法理解,可能需要咖啡......
    • 谢谢。让我知道是否有任何部分我可以帮助更好地解释。
    • 这正是我想要的,谢谢@StriplingWarrior
    【解决方案2】:

    您希望并行化for,而不是每个循环周期内的工作。使用Parallel.ForEach

    【讨论】:

    • 只有键操作不是线程安全的,读取键是线程安全的,而且他没有在代码中显示他如何使用字典。一个普通的 Dictionary&lt;&gt; 可能可能没问题。
    • OP 明确表示他正在尝试填充字典,这意味着他将调用 Add
    • ... 或使用:ConcurrentDictionary&lt;TKey,TValue&gt; documentation
    【解决方案3】:

    试试这个代码:

    
            public async Task<(string name, int id)> Aggregate(int id)
            {
                var result = await this.tableauService.GetUsersInTableauGroup(id);
                return (result, id);
            }
    
    ...
                var tasks = await Task.WhenAll(groups.Select(g => Aggregate(g.Id)));
    
                var dict = tasks.ToDictionary(k => k.id, k => k.name);
    
    

    它将异步运行所有 API 调用,一旦所有这些请求完成,我们就可以安全地从结果中创建字典

    【讨论】:

      猜你喜欢
      • 2018-08-11
      • 2017-07-26
      • 1970-01-01
      • 2017-12-19
      • 2018-10-16
      • 1970-01-01
      • 1970-01-01
      • 2018-01-20
      • 1970-01-01
      相关资源
      最近更新 更多