1

I've been reading the following post, specifically this point:

On your application’s entry point method, e.g. Main. When you await an instance that’s not yet completed, execution returns to the caller of the method. In the case of Main, this would return out of Main, effectively ending the program.

I've been trying to do that, but I can't seem to make it exit. Here's the code I have:

class Program
{
    // ending main!!!
    static async Task Main(string[] args)
    {
        Task<Task<string>> t = new Task<Task<string>>(async () =>
        {
            Console.WriteLine("Synchronous");
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("Synchronous");
                Console.WriteLine("Synchronous I is: " + i);
                await Task.Run(() => { Console.WriteLine("Asynchronous"); });
                await Task.Run(() => { for (int j = 0; j < 1000; j++) { Console.WriteLine( "Asynchronous, program should have exited by now?"); }});
            }
            return "ASD";
        });
        t.Start();
        await t;
    }
}

What exactly am I missing here? Shouldn't the program exit upon hitting the line await t; or by following through the thread at await Task.Run(() => { Console.WriteLine("Asynchronous"); });?

This is a Console application's main method.

Kami
  • 19,134
  • 4
  • 51
  • 63
SpiritBob
  • 2,355
  • 3
  • 24
  • 62
  • The code sample works as described in the blurb. You may get some output from for loop, but it will be terminated before all the tasks are completed. – Kami Nov 01 '19 at 12:17
  • 4
    The article you linked is from 2012, which predates the addition of `async` support to Main(). – Matthew Watson Nov 01 '19 at 12:18
  • @MatthewWatson Could you please provide a reference to the update/material? Was anything else changed in the way await operates? I'm trying to learn more about it. – SpiritBob Nov 01 '19 at 12:19
  • 1
    @SpiritBob the documentation itself explains this. Even the article you used explains that back then, you *couldn't* use `async Task`. The very fact that you can now means things have changed and you don't need all those tasks. – Panagiotis Kanavos Nov 01 '19 at 12:22
  • 1
    You can write just `await Task.Run(()=> { Console.WriteLine("Synchronous"); (...) for (int j = 0; j < 1000; j++) { ... } });`, removing the 2 other tasks in there. – Jimi Nov 01 '19 at 12:22
  • In fact, *no* article uses `new Task()` and `Start()`. Tasks aren't threads and there's no reason to create them like this. They are *promises* that something will complete and produce something in the *future*. To start a task just use `Task.Run`. In your code, just remove the first two and last 3 lines of `Main()` – Panagiotis Kanavos Nov 01 '19 at 12:24
  • @PanagiotisKanavos how so? I can see them using async Task, or you meant making the Main method async was forbidden? – SpiritBob Nov 01 '19 at 12:24

1 Answers1

3

The article you linked is from 2012, which predates the addition of async support to Main(), which is why what it's talking about seems wrong.

For the current implementation, consider the following code:

public static async Task Main()
{
    Console.WriteLine("Awaiting");
    await Task.Delay(2000);
    Console.WriteLine("Awaited");
}

This gets converted by the compiler as follows (I used "JustDecompile" to decompile this):

private static void <Main>()
{
    Program.Main().GetAwaiter().GetResult();
}

public static async Task Main()
{
    Console.WriteLine("Awaiting");
    await Task.Delay(2000);
    Console.WriteLine("Awaited");
}

Now you can see why the program doesn't exit.

The async Task Main() gets called from static void <Main>() which waits for the Task returned from async Task Main() to complete (by accessing .GetResult()) before the program exits.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276