it-swarm.com.ru

жду vs Task.Wait - тупик?

Я не совсем понимаю разницу между Task.Wait и await.

У меня есть что-то похожее на следующие функции в службе ASP.NET WebAPI:

public class TestController : ApiController
{
    public static async Task<string> Foo()
    {
        await Task.Delay(1).ConfigureAwait(false);
        return "";
    }

    public async static Task<string> Bar()
    {
        return await Foo();
    }

    public async static Task<string> Ros()
    {
        return await Bar();
    }

    // GET api/test
    public IEnumerable<string> Get()
    {
        Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());

        return new string[] { "value1", "value2" }; // This will never execute
    }
}

Где Get будет в тупике.

Что может вызвать это? Почему это не вызывает проблемы, когда я использую блокирующее ожидание, а не await Task.Delay?

135
ronag

Wait и await - хотя и схожи концептуально - на самом деле совершенно разные.

Wait будет синхронно блокироваться до завершения задачи. Таким образом, текущий поток буквально блокируется в ожидании завершения задачи. Как правило, вы должны использовать «async до конца»; то есть не блокируйте код async. В моем блоге я подробно разбираюсь с как блокировка в асинхронном коде вызывает тупик .

await будет асинхронно ожидать завершения задачи. Это означает, что текущий method «приостановлен» (его состояние фиксируется), и метод возвращает вызывающей стороне незавершенную задачу. Позже, когда выражение await завершится, оставшаяся часть метода запланирована как продолжение.

Вы также упомянули «кооперативный блок», под которым я предполагаю, что вы имеете в виду задачу, над которой вы Waiting можете выполнить в ожидающем потоке. Есть ситуации, когда это может произойти, но это оптимизация. Есть много ситуаций, когда это не может произойти, например, если задача предназначена для другого планировщика, или если она уже запущена, или если это не кодовая задача (например, в вашем примере кода: Wait не может выполнить Delay задача встроенная, потому что нет кода для этого).

Вы можете найти мое async/await введение полезным.

200
Stephen Cleary

На основании того, что я прочитал из разных источников:

Выражение await не блокирует поток, в котором оно выполняется. Вместо этого он заставляет компилятор зарегистрировать оставшуюся часть асинхронного метода как продолжение ожидаемой задачи. Затем управление возвращается к вызывающей стороне асинхронного метода. Когда задача завершается, она вызывает ее продолжение, и выполнение асинхронного метода возобновляется с того места, где оно было остановлено.

Чтобы дождаться завершения одного task , вы можете вызвать его метод Task.Wait. Вызов метода Wait блокирует вызывающий поток до тех пор, пока один экземпляр класса не завершит выполнение. Метод Wait () без параметров используется для безоговорочного ожидания завершения задачи. Задача имитирует работу, вызывая метод Thread.Sleep для сна в течение двух секунд.

Эта статья также хорошо читать.

0
Ayushmati