This is happening because the console application is exiting before the output is written to the console by the background tasks.
If you add Console.ReadLine() to the end of the method and try running it without any .Wait() you'll see that it outputs 1 and 2 as expected.
So, why does this happen?
Well, it's because there's an overhead associated with the first write to the console - an overhead that doesn't occur for subsequent writes.
So when you have no Wait() the first Console.WriteLine() has not had time to finish before the program exits.
However, when you add the Wait() to the first task then the first Console.WriteLine() has (obviously) finished and the second Console.WriteLine() doesn't have the overhead associated with the first one, and it has time to finish before the program exits.
(This is a race condition and the actual results may vary over different runs and different environments.)
We can perform some rudimentary timings to show the difference in time taken between the first call to Console.WriteLine() and the second call. (Note: Normally I use Bench.Net for timings, but that wouldn't work very well for this particular case.)
static void Main()
{
Stopwatch sw = Stopwatch.StartNew();
Console.WriteLine("1");
sw.Stop();
Console.WriteLine("First Console.WriteLine() took " + sw.Elapsed);
sw.Restart();
Console.WriteLine("2");
sw.Stop();
Console.WriteLine("Second Console.WriteLine() took " + sw.Elapsed);
}
For a release build on my PC this outputs:
1
First Console.WriteLine() took 00:00:00.0060951
2
Second Console.WriteLine() took 00:00:00.0000624
As you can see, the second call is almost 100 times faster than the first call. If the program exits in somewhat less than 0.0060951 seconds, no output will be seen.
But if a Console.WriteLine() has previously been executed, the program will have to exit in less than 0.0000624 seconds for the output not to appear (approximately!).
You can also demonstrate this by adding a Console.WriteLine() to the start of the program, so that the subsequent calls avoid the overhead of the first call:
Console.WriteLine("Priming");
void MyMethod1()
{
Console.WriteLine(1);
}
void MyMethod2(Task MyTask)
{
Console.WriteLine(2);
}
Task MyTask1 = new Task(MyMethod1);
MyTask1.Start();
Task MyTask2 = MyTask1.ContinueWith(MyMethod2); //Why it is work?
If you do that, the output is 1 and 2 - even without the call to MyTask1.Wait();.
Again, note that this is a race condition, and actual results may vary. It relies on the calls to WriteLine() completing before the program actually exits.
Your takeaway from this should be that multithreading is tricky, and you have to do it correctly otherwise weird stuff like this will happen!