Асинхронное ожидание работает синхронно - PullRequest
0 голосов
/ 22 ноября 2018

Я пытаюсь изучить async / await и создал следующий тестовый код, однако он работает синхронно, и я не уверен, почему.

    class Program
    {                
        static void Main()
        {
            TestAsync testAsync = new TestAsync();
            testAsync.Run();

            Console.Read();
        }        
    }

    public class TestAsync
    {
        public async void Run()
        {
            Task<int> resultTask = GetInt();
            Console.WriteLine("2)");
            int x = await resultTask;
            Console.WriteLine("4)");
        }
        public async Task<int> GetInt()
        {
            Task<int> GetIntAfterLongWaitTask = GetIntAfterLongWait();
            Console.WriteLine("1)");
            int x = await GetIntAfterLongWaitTask;//Expecting execution to go back to Run() since it's not done yet.
            Console.WriteLine("3)");
            return x;
        }

        public async Task<int> GetIntAfterLongWait()
        {
            for (int i = 0; i < 500000000; i++)
            {
                if (i % 10000000 == 0)
                {
                    Console.WriteLine(i);
                }                
            }

            return 23;
        }
    }

Вывод:

<long list of ints>
1)
3)
2)
4)

Я ожидал, что оно будет

<long list of ints>
1)
2)
3)
4)

С 1), находящимся где-то среди длинного списка целых чисел.

Почему он работает синхронно?

1 Ответ

0 голосов
/ 22 ноября 2018

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

По этой причине ваши асинхронные методы должны выполняться максимально быстро.Не выполняйте никаких операций блокировки в таком методе настройки.Ваш метод GetIntAfterLongWait является блокирующей операцией, и, поскольку он не содержит никаких await s, весь контент будет выполняться немедленно при вызове метода (без каких-либо await в методе нет ничего для установки асинхронного продолжения).).Об этом также должно быть предупреждение.

Если у вас есть операция блокировки, которую вы хотите выполнить в асинхронном методе, возможный вариант - запланировать ее с помощью вызова await Task.Run(() => MyLongOperation());.

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

public async Task<int> GetIntAfterLongWait()
{
    await Task.Run(() =>
    {
        for (int i = 0; i < 500000000; i++)
        {
            if (i % 10000000 == 0)
            {
                Console.WriteLine(i);
            }                
        }
    });

    return 23;
}

Подробнее см. По ссылке выше.

Обновление:

Эта версия будет печатать:

1)
2)
<long list of ints> - but 0 can be before even 1) as Task.Run uses another thread
3)
4)
...