жду 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?

 ronag30 окт. 2012 г., 15:36
@Servy: я вернусь с репо, как только у меня будет время. На данный момент это работает сTask.Delay(1).Wait() что достаточно хорошо
 Servy30 окт. 2012 г., 15:38
Task.Delay(1).Wait() в основном то же самое, чтоThread.Sleep(1000), В реальном производственном коде это редко уместно.
 Servy30 окт. 2012 г., 16:10
@ronag, потому что у вас естьConfigureAwait(false) a Один позвонитьBar или жеRos не заходит в тупик, но поскольку у вас есть перечислимое, которое создает более одного, а затем ожидает всех из них, первый бар заблокирует второй. если тыawait Task.WhenAll вместо ожидания выполнения всех задач, чтобы не блокировать контекст ASP, вы увидите, что метод возвращает нормально.
 Servy30 окт. 2012 г., 16:16
@ronag Ваш другой вариант будет добавить.ConfigureAwait(false) весь путь вверх по дереву пока вы не заблокируете, таким образом, ничего неКогда-либо пытаясь вернуться к основному контексту; это будет работать. Другим вариантом будет ускорение внутреннего контекста синхронизации.Ссылка, Если вы положитеTask.WhenAll вAsyncPump.Run это эффективно блокирует все это без необходимостиConfigureAwait где угодно, но это, вероятно, слишком сложное решение.
 Servy30 окт. 2012 г., 15:27
Ваш код как есть не будет компилироваться; Ваш метод указан как имеющий обаvoid а такжеTask как возвращаемые типы. Пожалуйста, предоставьте скомпилированный код, который демонстрирует проблему. Да, и когда я исправляю эту ошибку и запускаю код, я не зацикливаюсь (как я и ожидал).

Ответы на вопрос(2)

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

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

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

 Marc Gravell♦06 дек. 2018 г., 14:54
«Разве это не технически неверно? Может, кто-нибудь уточнит?» - могу я уточнить; ты спрашиваешь это как вопрос? (Я просто хочу уточнить, спрашиваете ли вы против ответа). Если вы спрашиваете: это может работать лучше как отдельный вопрос; вряд ли здесь соберутся новые ответы в качестве ответа
 Ayushmati06 дек. 2018 г., 16:03
Я ответил на вопрос и задал отдельный вопрос за сомнения, которые у меня были здесьstackoverflow.com/questions/53654006/... Спасибо @MarcGravell. Можете ли вы удалить свой голос за удаление за ответ сейчас?
 Marc Gravell♦06 дек. 2018 г., 16:30
"Можете ли вы удалить свой голос за удаление за ответ сейчас?" - это не мое; Благодаря ♦, любое такое голосование мной вступило бы в силу немедленно. Однако я не думаю, что это отвечает на ключевые вопросы, касающиеся тупикового поведения.
Решение Вопроса

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

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

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

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

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

 ronag30 окт. 2012 г., 15:20
Я думаю, что есть недоразумение,Wait работает отличноawait тупики.
 Stephen Cleary30 окт. 2012 г., 15:23
Нет, планировщик задач этого не сделает.Wait блокирует поток и не может использоваться для других целей.
 Stephen Cleary06 дек. 2016 г., 20:19
@hexterminator: Это сделано специально - он отлично работает для приложений пользовательского интерфейса, но, как правило, мешает приложениям ASP.NET. ASP.NET Core исправил это, удаливSynchronizationContextпоэтому блокировка в запросе ASP.NET Core больше не блокируется.
 Stephen Cleary05 сент. 2017 г., 19:03
@JoePhillips: см. Хаки в моемАсинхронная статья Браунфилда.
 Servy30 окт. 2012 г., 15:37
@ronag Полагаю, вы просто перепутали имена методов, и ваша тупиковая ситуация была вызвана кодом блокировки и работала сawait код. Либо это, либо тупик не был связан ни с чем, и вы неправильно диагностировали проблему.

Ваш ответ на вопрос