Home > front end >  C# - async/await print order
C# - async/await print order

Time:05-30

I am trying to understand how async and await works so i wrote this little program to try and print "b" before "a" but it's not working and i can't figure it out.. any help? :)

public class program
{
    static async Task Main()
    {
        await a();
        b();
    }

    async static Task a()
    {
        Console.WriteLine("Waiting for a");
        for (int i = 0; i < 100000000; i  )
            if (i % 1000000 == 0)
                Console.Write(".");
        Console.WriteLine("\na");
    }

    static void b()
    {
        Console.WriteLine("b");
    }
}

CodePudding user response:

Lets refine your code. First it doesn't work, because you told the code to await a(), and so nothing after that line can run before (or during) it. Lets fix it:

    static async Task Main()
    {
        var task = a();
        b();
        await task;
    }

However that is not enough, it still doesn't work. It still runs a() before b() because your a method is not asynchronous. In fact it is synchronous. Just because you use async/await it doesn't make the code automatically asynchronous. You'll need more than that. One way is to add await Task.Yield() which is truely asynchronous call, even though it does nothing (except for allowing the switch to happen). Like this:

    async static Task a()
    {
        Console.WriteLine("Waiting for a");
        for (int i = 0; i < 100000000; i  )
            if (i % 1000000 == 0)
            {
                Console.Write(".");
                await Task.Yield();
            }
        Console.WriteLine("\na");
    }

Now you will see b() running in the middle of a(). You can play around with the await Task.Yield(); call, and put it in different places to see different result.

This is still a bit primitive example. It would be better to make b() asynchronous as well. And use delays. Like this:

public class program
{
    static async Task Main()
    {
        var task1 = a();
        var task2 = b();
        await task1;
        await task2;
    }

    async static Task a()
    {
        Console.WriteLine("Waiting for a");
        for (var i = 0; i < 100; i  )
        {
            Console.Write(".");
            await Task.Delay(20);
        }
        Console.WriteLine("\na");
    }

    static async Task b()
    {
        await Task.Delay(200);
        Console.WriteLine("b");
    }
}

Note that I've slightly modified your a() so that it is more time dependent, less cpu-speed dependent.

Of course you have a thread-safety issue now, which in this case is ok since Console and Task methods are thread-safe. But generally you have to be aware that when two or more Tasks run concurrently then they may run on different threads, and thus you have to make the code thread-safe.

CodePudding user response:

There are 2 problems.

  1. Await is being used incorrectly

You use await to ensure whichever async method is called is completed before any subsequent code is executed.

As freakish said in his answer, you can assign the task from method a to a variable and await it after method b.

  1. Method a isn't actually asynchronous

There isn't any thing that can actually be awaited in the method so it would just run synchronously and complete before method b. Adding something that can be awaited like Task.Yeild (as freakish has stated) would resolve the issue.

I would recommend reading more about asynchronous programming, here is a good place to start: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/

  • Related