Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
353 views
in Technique[技术] by (71.8m points)

c# - Async Await Running Synchronously

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...