Подтвердить что ты не робот

Ожидание Task.Delay() vs. Task.Delay(). Wait()

В С# у меня есть следующие два простых примера:

[Test]
public void TestWait()
{
    var t = Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Start");
        Task.Delay(5000).Wait();
        Console.WriteLine("Done");
    });
    t.Wait();
    Console.WriteLine("All done");
}

[Test]
public void TestAwait()
{
    var t = Task.Factory.StartNew(async () =>
    {
        Console.WriteLine("Start");
        await Task.Delay(5000);
        Console.WriteLine("Done");
    });
    t.Wait();
    Console.WriteLine("All done");
}

В первом примере создается задача, которая печатает "Старт", ждет 5 секунд печати "Готово", а затем завершает задачу. Я жду завершения задачи и затем распечатаю "Все сделано". Когда я запускаю тест, он делает так, как ожидалось.

Второй тест должен иметь такое же поведение, за исключением того, что ожидание внутри задачи должно быть неблокирующим из-за использования async и ожидания. Но этот тест просто печатает "Старт", а затем сразу "Все сделано" и "Готово" никогда не печатается.

Я не знаю, почему я получаю такое поведение: S Любая помощь будет очень признательна:)

4b9b3361

Ответ 1

Второй тест состоит из двух вложенных задач, и вы ожидаете самого внешнего, чтобы исправить это, вы должны использовать t.Result.Wait(). t.Result получает внутреннюю задачу.

Второй метод примерно эквивалентен этому:

public void TestAwait()
{
  var t = Task.Factory.StartNew(() =>
            {
                Console.WriteLine("Start");
                return Task.Factory.StartNew(() =>
                {
                    Task.Delay(5000).Wait(); Console.WriteLine("Done");
                });
            });
            t.Wait();
            Console.WriteLine("All done");
}

Вызывая t.Wait(), вы ждете самой внешней задачи, которая немедленно возвращается.


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

    [Test]
    public async Task TestCorrect() //note the return type of Task. This is required to get the async test 'waitable' by the framework
    {
        await Task.Factory.StartNew(async () =>
        {
            Console.WriteLine("Start");
            await Task.Delay(5000);
            Console.WriteLine("Done");
        }).Unwrap(); //Note the call to Unwrap. This automatically attempts to find the most Inner `Task` in the return type.
        Console.WriteLine("All done");
    }

Еще лучше использовать Task.Run, чтобы начать асинхронную операцию:

    [TestMethod]
    public async Task TestCorrect()
    {
        await Task.Run(async () => //Task.Run automatically unwraps nested Task types!
        {
            Console.WriteLine("Start");
            await Task.Delay(5000);
            Console.WriteLine("Done");
        });
        Console.WriteLine("All done");
    }