@glaucidium

Как правильно организовать цикл по таскам?

Как запустить обработку в цикле асинхронных(await) методов, и когда они (вместе с кодом снизу await) завершаться, продолжить работу программы синхронно?
Предполагаю, что это платиновый вопрос, но в гугле ответа не нашёл.
По конкретнее - пытаюсь пройтись get-запросом по списку сайтов, и в зависимости от ответа что-то делать с сайтом дальше. А по истечении цикла, продолжить программу синхронно.

Вот запускающий код.
List<Tuple<string, string>> addresses; // uri и host
List<Task> workTasks = new List<Task>();

foreach (var address in addresses)
{
	workTasks.Add(ProcessingRequset_await(address));
	//workTasks.Add(ProcessingRequset_wait(address));	
}
Task.WaitAll(workTasks.ToArray());
Console.WriteLine("Задачи завершены");
Console.ReadKey();

Вот первый вариант обработки ответа. Он быстрый, но задача считается завершённой, когда достигнет await. Поэтому при окончании цикла, обработка ответов ещё продолжается.
public static Task ProcessingRequset_await(Tuple<string, string> address)
        {
            Task result = new Task(async () =>
            {
                HttpWebResponseLink httpWebResponseLink = new HttpWebResponseLink();

                try
                {
                    HttpWebResponse response = (HttpWebResponse) await GetResponseAsync(address.Item1, address.Item2);
                    httpWebResponseLink.IsHttpWebResponseTaked = true;
                    httpWebResponseLink.httpWebResponseLink = response;
                }
                catch (Exception e)
                {
                    httpWebResponseLink.IsHttpWebResponseTaked = false;
                }
    	        // логгирование и обработка результатов запроса
            });
            result.Start();
            return result;
        }

Если в этом коде заменить:
HttpWebResponse response = (HttpWebResponse) await GetResponseAsync(address.Item1, address.Item2);
на
Task<WebResponse> taskResponse = GetResponseAsync(address.Item1, address.Item2);
taskResponse.Wait();
HttpWebResponse response = (HttpWebResponse)taskResponse.Result;

то судя по логам, задачи запускаются как-бы через секунду, а завершаются почти одновременно, и время работы цикла дольше. Зато, цикл оканчивается когда задачи завершены полностью.

Эта функция просто скрывает порождение реквестных тасков.
public static Task<WebResponse> GetResponseAsync(string uri, string host)
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
            request.Method = "GET";
            request.ProtocolVersion = HttpVersion.Version11;
            request.Host = host;

            Task<WebResponse> requestTask = request.GetResponseAsync();
            return requestTask;
        }
  • Вопрос задан
  • 237 просмотров
Решения вопроса 1
@glaucidium Автор вопроса
Нашёл решение.
На сколько понял из https://msdn.microsoft.com/en-us/library/mt674893.aspx, async Task метод, не имеющий return, но имеющий await автоматически выдаёт Task.

В общем, переписал тот метод вот так, и всё заработало как надо. Логи говорят, что задачи начинаются почти одновременно, и завершаются когда приходят соответствующие ответы на реквесты. И отписка "Задачи завершены" происходит только после завершения всех задач.
public static async Task ProcessingRequset(Tuple<string, string> address)
        {
                HttpWebResponseLink httpWebResponseLink = new HttpWebResponseLink();
                try
                {
                    HttpWebResponse response = (HttpWebResponse) await GetResponseAsync(address.Item1, address.Item2);
                    httpWebResponseLink.IsHttpWebResponseTaked = true;
                    httpWebResponseLink.httpWebResponseLink = response;
                }
                catch (Exception e)
                {
                    httpWebResponseLink.IsHttpWebResponseTaked = false;
                }
	              // логгирование и обработка результатов запроса
        }


Также добавлю, что нашёл ещё более простой способ обработки списка долго ждущими операциями:
var tasks = list.Select(async x =>
{
    var y = await IOProcessing(x);
    var z = await IOProcessing(y);
    Console.WriteLine(z);
});
Task.WhenAll(tasks).Wait();
Console.WriteLine(«Tasks completed»);
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@tex0
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы