Async Await Running Synchronously

天大地大妈咪最大 提交于 2020-12-21 03:54:38

问题


I'm trying to learn async/await and created the following test code, however it is running synchronously and I'm not sure why.

    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;
        }
    }

Output is:

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

I expected it to be

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

With 1) being somewhere amongst the long list of ints.

Why is it running synchronously?


回答1:


Confusingly enough, the async keyword will not turn your methods magically asynchronous. Instead, you can consider async methods as a setup for a state machine (see a detailed explanation here), where you schedule the chain of operations by the await calls.

For that reason, your async methods must execute as fast as possible. Do not do any blocking operation in such a setup method. Your GetIntAfterLongWait method is a blocking operation and since it does not contain any awaits the whole content will be executed immediately when the method is called (without any await there is nothing in the method to setup for an async continuation). There must be also a warning about that.

If you have a blocking operation, which you want to execute in the async method, a possible option is to schedule it by an await Task.Run(() => MyLongOperation()); call.

So for example the following example will return immediately because there is nothing to execute before the first await. The return statement will be executed asynchronously as a continuation after the inner awaited task finished:

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

    return 23;
}

For more details see the link above.

Update:

This version will print:

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


来源:https://stackoverflow.com/questions/53425208/async-await-running-synchronously

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!