There is some misunderstanding with the operation of asynchronous code, in connection with which I ask for help. The following function hangs up the program:

private List<ContractsList> GetContractsDetail(contracts) { List<string> contractsList = new List<string>(); // Сюда буду ложить ответы 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<string, string> data = new Dictionary<string, string>() { ["access_token"] = token, ["contract_id"] = contracts[i] }; // Данные для GET запроса requests[i] = ContractRequest.Get(Uri, data); // Моя обертка над HttpClient.GetAsync } Task.WaitAll(requests); // Тут зависает программа // Тут еще код, который я не дописал return contractsList; } 

According to information on the Internet I do not fully understand:

  1. Does WaitAll like await ? And if so, why does the program hang?
  2. Do my Tasks start at all?
  3. Where in the code am I wrong? =)

Reported as a duplicate by members of Pavel Mayorov , cheops , zRrr , aleksandr barakin , PashaPash c # 11 May '16 at 6:50 .

A similar question was asked earlier and an answer has already been received. If the answers provided are not exhaustive, please ask a new question .

    2 answers 2

    Not. Task.Wait , Task.WaitAll is not await at all! await is an asynchronous continuation, Wait is synchronous waiting.

    You have a deadlock. You work in the UI stream - and therefore all your tasks put their continuations in the queue of events. As long as this queue does not "turn on", the task will not be completed. But at the same time you blocked the queue with synchronous waiting!

    The correct way to get rid of deadlocks is to use asynchronous code at all levels. Yes, for this, the GetContractsDetail function GetContractsDetail must also be made asynchronous:

     await Task.WhenAll(requests); 

    A kostylny, but an easier way is to bring tasks to the thread pool:

      requests[i] = Task.Run(() => ContractRequest.Get(Uri, data)); 

    Another crutch and easy way is to put .ConfigureAwait(false) on the first await operator in the ContractRequest.Get method

    • Thank. Did I understand correctly that await Task.WhenAll(requests); - will work the same, if only I wrote like this . Well, figuratively speaking. - user200141
    • @ Oleg yes, you understood correctly. - Pavel Mayorov
    • You helped me out) - user200141
    • Pavel, can I have another little question? Suppose in this example I used WhenAll() as follows: string[] resp = await Task.WhenAll(requests); . Question: The array of answers resp will be filled with elements in the order in which requests are stored in requests ? Or as requests are completed? - user200141
    • In the order of the array of requests - Pavel Mayorov

    WaitAll does not work like await .

    • WaitAll blocks the current thread until the WaitAll completes.
    • await frees the current thread, and puts the rest of the method in the continuation to the task in the appropriate context (GUI stream or stream with the same HttpContext).

    Accordingly, if the code inside your wrapper decides to put the task to execute in the current context (GUI or ASP.NET), then it will wait for the context to be released. And WaitAll will keep the flow (and context), waiting for the end of the execution of the code - and everything hangs.

    This is quite extensively disclosed in MSDN Magazine, Async / Await - Best Practices in Asynchronous Programming / Async All the Way

    Do not mix async / await and direct Wait .

    • Thanks, it became clearer. - user200141