Страницы

Поиск по вопросам

четверг, 15 ноября 2018 г.

Асинхронный код (Task.WaitAll) вешает программу [дубликат]

На данный вопрос уже ответили: Зависает оператор `await` в оконном приложении / программа висит при вызове Task.Result или Wait 1 ответ Есть некоторое недопонимание с работой асинхронного кода, в связи с чем прошу помощи. Следующая функция вешает программу:
private List GetContractsDetail(contracts) { List contractsList = new List(); // Сюда буду ложить ответы Task[] requests = new Task[contracts.Length]; // Создаю массив для моих тасков
Uri Uri = new Uri(Settings.CONTRACT_DETAIL_URI);
for (int i = 0; i < contracts.Length; i++) // По каждому контракту { HttpRequest ContractRequest = new HttpRequest(); //Это мой класс для работы с HttpClient
Dictionary data = new Dictionary() { ["access_token"] = token, ["contract_id"] = contracts[i] }; // Данные для GET запроса requests[i] = ContractRequest.Get(Uri, data); // Моя обертка над HttpClient.GetAsync }
Task.WaitAll(requests); // Тут зависает программа // Тут еще код, который я не дописал
return contractsList; }
По информации в интернете не до конца понимаю:
работает ли WaitAll как await? И если да, то почему виснет программа? стартуют ли вообще мои Таски? в каком месте кода я не прав? =)


Ответ

Нет. Task.Wait, Task.WaitAll - это совсем не await! await - это асинхронное продолжение, Wait же является синхронным ожиданием.
У вас взаимоблокировка. Вы работаете в потоке UI - а потому все ваши задачи свои продолжения ставят в очередь событий. Пока эта очередь не "провернется" - задача не будет выполнена. Но саму очередь вы при этом заблокировали синхронным ожиданием!
Правильный способ избавиться от взаимоблокировки - использовать асинхронный код на всех уровнях. Да, для этого саму функцию GetContractsDetail нужно тоже сделать асинхронной:
await Task.WhenAll(requests);
Костыльный, но более простой способ - вынести задачи в пул потоков:
requests[i] = Task.Run(() => ContractRequest.Get(Uri, data));
Еще один костыльный и простой способ - проставить .ConfigureAwait(false) на первом операторе await в методе ContractRequest.Get

Комментариев нет:

Отправить комментарий