【问题标题】:async methods in a foreach and add results in a listforeach 中的异步方法并将结果添加到列表中
【发布时间】:2019-05-28 20:38:44
【问题描述】:

我想在 foreach 中运行几个异步方法。返回值应写入列表。

该方法在 WPF 应用程序中执行。 GetItemPricesFromJsonAsync 方法从网络数据中获取。

public async Task LoadBlackMarketListView(List<MarketAnalysisManager.ItemTier> tiers, List<MarketAnalysisManager.ItemLevel> levels, 
            List<MarketAnalysisManager.ItemQuality> quialityList, string outdatedHours, string profit, Location? location)
        {
            await Task.Run(async () =>
            {
                var blackMarketSellObjectList = new List<BlackMarketSellObject>();

                var items = await MarketAnalysisManager.GetItemListAsync(tiers, levels);

                await Dispatcher.InvokeAsync(() =>
                {
                    PbBlackMarketMode.Minimum = 0;
                    PbBlackMarketMode.Maximum = items.Count;
                    PbBlackMarketMode.Value = 0;
                    GridBlackMarketMode.IsEnabled = false;
                    LvBlackMarket.Visibility = Visibility.Hidden;
                    PbBlackMarketMode.Visibility = Visibility.Visible;
                });

                foreach (var item in items)
                {
                    var allItemPrices = await MarketAnalysisManager.GetItemPricesFromJsonAsync(item.UniqueName, true);
                    if (allItemPrices.FindAll(a => a.City == Locations.GetName(Location.BlackMarket)).Count <= 0)
                    {
                        await IncreaseBlackMarketProgressBar();
                        continue;
                    }

                    blackMarketSellObjectList.AddRange(await GetBlackMarketSellObjectList(item, quialityList, allItemPrices, outdatedHours, profit, location));

                    await IncreaseBlackMarketProgressBar();
                }

                await Dispatcher.InvokeAsync(() =>
                {
                    LvBlackMarket.ItemsSource = blackMarketSellObjectList;
                    PbBlackMarketMode.Visibility = Visibility.Hidden;
                    LvBlackMarket.Visibility = Visibility.Visible;
                    GridBlackMarketMode.IsEnabled = true;
                });
            });

        }

目前看来他一次只做一件事。

运行... 0

结束... 0

运行... 1

结束... 1

运行... 2

结束... 2

【问题讨论】:

  • await 暂停执行,直到等待的任务完成,从而使 foreach 同步运行
  • 是的,确实如此,但是如何才能最好地让几件事情并行运行?
  • 如果您想继续使用纯异步/等待,请查看my answer。如果您想使用 Parallel 类,请查看this answer by Michal
  • 只是我注意到的一件事.. 你为什么在函数的第一行执行 await Task.Run(async () => ...?我看不出有什么好处给函数带来了另一层嵌套。如果你不这样做并且将所有代码直接放入函数中而没有匿名中间函数,你应该得到完全相同的东西还是我错过了什么?
  • 没错@Joelius。感谢您的提示。

标签: c# wpf foreach async-await


【解决方案1】:

您需要存储任务,而不是等待它们。然后,您可以等待所有这些。
试试这个(用我的代码替换你的 foreach)。
我还建议您使用真实方法而不是匿名方法,它更具可读性。

List<Task> tasks = new List<Task>();
foreach (var item in items)
{
    tasks.Add(Task.Run(async () => 
    {
        var allItemPrices = await MarketAnalysisManager.GetItemPricesFromJsonAsync(item.UniqueName, true);
        if (allItemPrices.FindAll(a => a.City == Locations.GetName(Location.BlackMarket)).Count <= 0)
        {
            await IncreaseBlackMarketProgressBar();
            return;
        }

        blackMarketSellObjectList.AddRange(await GetBlackMarketSellObjectList(item, quialityList, allItemPrices, outdatedHours, profit, location));

        await IncreaseBlackMarketProgressBar();
    }));
}

await Task.WhenAll(tasks);

注意:现在有一个 return 而不是 continue 因为这是一个匿名函数,你只需要在那里结束函数而不是继续 foreach。

【讨论】:

  • 效果很好。不幸的是,加载时间并不短。所以对用户来说变化不大。
  • @Triky313 如果你有太多的项目,那么它甚至会减慢程序。
  • @Triky313 如果这不能加快进程,则可能存在其他一些依赖关系,或者花费的时间非常短。我使用 int 数组作为项目对其进行了测试,将等待转换为简单的延迟(Task.Delay)并在 int 为奇数时返回。与你原来的方式相比,我的方式加快了代码速度。
  • @Rekshino 你能详细说明一下吗?听起来很有趣,我不太明白你的意思。
猜你喜欢
  • 1970-01-01
  • 2021-11-23
  • 1970-01-01
  • 1970-01-01
  • 2018-06-18
  • 1970-01-01
  • 1970-01-01
  • 2011-07-13
  • 2016-02-04
相关资源
最近更新 更多