Асинхронные методы в foreach и добавить результаты в список

Я хотел бы запустить несколько методов asyncron в 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 выполняться синхронно.

Tony Abrams 28.05.2019 13:10

Да, это правда, но как мне сделать так, чтобы несколько вещей работали параллельно?

Triky313 28.05.2019 13:20

Если вы хотите продолжить использовать простой async/await, проверьте мой ответ. Если вы хотите использовать класс Parallel, проверьте этот ответ Михала.

Joelius 28.05.2019 13:27

Я только что заметил.. почему вы делаете await Task.Run(async () => ... в первой строке функции? Я не вижу в этом никакого преимущества, и это добавляет еще один уровень вложенности в функцию , Если вы этого не сделаете и поместите весь код непосредственно в функцию без анонимной промежуточной функции, вы должны получить то же самое, или я что-то упустил?

Joelius 28.05.2019 14:23

Это правильно @Joelius. Спасибо за подсказку.

Triky313 28.05.2019 14:45
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
1 612
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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);

Примечание. Теперь вместо продолжения используется возврат, так как это анонимная функция, и вам просто нужно завершить функцию там, а не продолжать foreach.

Это прекрасно работает. К сожалению, время загрузки не меньше. Так что для пользователя это мало что меняет.

Triky313 28.05.2019 13:48

@Triky313 Если у вас слишком много элементов, это может даже замедлить работу программы.

Rekshino 28.05.2019 14:08

@ Triky313 Triky313 Если это не ускорит процесс, могут быть какие-то другие зависимости, или это займет очень мало времени. Я протестировал его с использованием массива int в качестве элементов, превратил ожидания в простые задержки (Task.Delay) и вернулся, когда int был нечетным. Мой способ немного ускорил код по сравнению с вашим первоначальным способом.

Joelius 28.05.2019 14:18

@Rekshino, не могли бы вы рассказать об этом подробнее? Звучит очень интересно, и я не совсем понимаю, что вы имеете в виду.

Joelius 28.05.2019 14:18

@Joelius См., например, Parallel.ForEach против Task.Factory.StartNew

Rekshino 28.05.2019 14:22

@ Рекшино, ааа, понятно. Я использую класс Parallel только для очень большого количества элементов, и, исходя из моего опыта, чаще всего этот порог не достигается. Я думаю, вам придется провести некоторые измерения, чтобы определить, какой из них работает лучше в этом случае. Я думаю, любой из них будет работать нормально.

Joelius 28.05.2019 14:30

@Joelius Хорошо, это немного быстрее, ты прав. Этот метод «MarketAnalysisManager.GetItemPricesFromJsonAsync (item.UniqueName, true)» занимает много времени, поскольку данные загружаются из Интернета. Нельзя ли распараллелить эти 1000 запросов... или так происходит с Task.Run()?

Triky313 28.05.2019 15:36

Что происходит, так это то, что он начинает выполнение, но затем уже запускает следующий, не дожидаясь завершения первого. После foreach мы ждем завершения всех задач (в настоящее время они выполняются параллельно (проверьте определение параллельности при использовании задач, если вам нужна дополнительная информация об этом)).

Joelius 28.05.2019 17:17

Если вы считаете, что этот метод недостаточно быстр, вы можете попробовать заставить его работать с классом Parallel. По моему опыту, случаев (в случайном программировании) меньше, когда класс Parallel превосходит мой метод. Не стесняйтесь попробовать другой метод, потому что иногда он дает вам удивительно большой прирост производительности.

Joelius 28.05.2019 17:21

@Joelius Разве нельзя повторно использовать задачу?

Ishani Gupta 09.02.2021 03:35

Другие вопросы по теме