Task WhenAny WhenAll
От: CyberRussia  
Дата: 15.11.20 19:25
Оценка:
Привет!

Пытаюсь разобраться в работе Task применительно к своей задаче (в целом она уже сделана на ThreadPool, но хочется с Task разобраться для самообразования).
Сама задача — нужно запросить сторонний сервис для получения данных, отправив в общей сложности примерно 15 000 запросов с различными уникальными аргументами. Если попробовать отправить сразу или почти сразу все 15 000, то сервис посчитает, что его ddos'ят и на время закроется от запросов приложения. Поэтому нужно ограничивать количество единовременных запросов. Так же, поскольку процесс не особо быстрый, нужно время от времени выводить на пользовательский интерфейс уведомления о ходе процесса. По окончанию всех (именно всех) запросов есть некие финальные действия.
Сейчас мне интересно лишь как это все делается силами Task.
Набросал, как мне это видится, использовав вместо реальных запросов и аргументов — иммитации, и не 15 000, а всего 30 — просто для понимания как вообще код писать с Task.
        static async void TastWrite()
        {
            object objLockAdd = new object(); // Объект для блокировки
            try
            {
                Action<object> action = (p) =>
                {
                    Console.WriteLine(p);
                    Random random = new Random();
                    Thread.Sleep(random.Next(700, 1500));
                }; // Код для выполнения в задаче

                List<string> baslList = new List<string>();// Множество данных (аргументов) необходимых к обработке
                for (int i = 1; i < 30; i++)
                {
                    baslList.Add(i.ToString());
                }
                List<Task> tasks = new List<Task>();// Список задач, за выполнением которых будем следить
                while (baslList.Count > 0)// Пока есть данные
                {
                    if (tasks.Count > 0)
                    {
                        Task finischTask = await Task.WhenAny(tasks); // Если задачи есть, то ждем завершения хотя бы одной
                        // Тут должен быть код промежуточной реакции, вывод в пользовательский интерфейс прогресса
                        tasks.Remove(finischTask); // Убираем из списка выполненну задачу
                    }
                    while (tasks.Count < 4 && baslList.Count > 0) // Контролируем, что задач не слишком много и данные еще имеются
                    {
                        lock (objLockAdd)
                        {
                            tasks.Add(new TaskFactory().StartNew(action, baslList[baslList.Count - 1])); // Добавляем новую задачу и сразу ее запускаем, чтобы не возникло конфликта с параметром
                            baslList.RemoveAt(baslList.Count - 1); // Удаляем обработанное данное из списка
                        }
                    }
                }
                await Task.WhenAll(tasks); // Ожидаем когда все задачи будут выполнены
                Console.WriteLine("Finisch"); // Выводим уведомление, когда абсолютно все завершено
            }
            catch (Exception ex) { }
        }

Или я в принципе не так понимаю работу с Task и писать надо иначе?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.