异步等待同步运行

时间:2018-11-22 06:42:04

标签: c# asynchronous 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 :(得分:3)

令人困惑的是,async关键字不会使您的方法神奇地异步化。相反,您可以考虑将async方法用作状态机的设置(请参见详细说明here),在该方法中,您可以通过await调用来调度操作链。

因此,您的异步方法必须尽快执行。在这种设置方法中请勿执行任何阻止操作。您的GetIntAfterLongWait方法是一个阻塞操作,由于它不包含任何await,因此在调用该方法时,整个内容将立即执行(没有任何await的方法为异步继续设置)。对此也必须有警告。

如果您有要在async方法中执行的阻止操作,则可能的选择是通过await Task.Run(() => MyLongOperation());调用来安排它。

因此,例如,下面的示例将立即返回,因为在第一个await之前无需执行任何操作。内部等待的任务完成后,return语句将作为继续执行异步执行:

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)