@Dan Dinu's answer from a previous question regarding asynchronous programming in C# provides a useful minimal example, which I have adapted as follows:
// From https://stackoverflow.com/questions/14455293/how-and-when-to-use-async-and-await
using System;
using System.Threading.Tasks;
namespace minimal_async_await_SE
{
internal class Program
{
public static async Task MyMethodAsync()
{
Task<int> longRunningTask = LongRunningOperationAsync();
// independent work which doesn't need the result of LongRunningOperationAsync
// can be done here
Console.WriteLine("Independent work");
//Call await on the task
int result = await longRunningTask;
Console.WriteLine(result);
}
public static async Task<int> LongRunningOperationAsync()
{
await Task.Delay(1000);
return 1;
}
static void Main(string[] args)
{
MyMethodAsync();
Console.WriteLine("Returned to Main");
//Console.ReadKey();
}
}
}
If I uncomment line 32, I get the following expected result:
Independent work
Returned to Main
1
Basically:
Main
callsMyMethodAsync
MyMethodAsync
callsLongRunningOperationAsync
LongRunningOperationAsync
then callsTask.Delay
, butawait
s it which suspends further evaluation of the enclosing methodLongRunningOperationAsync
, returning control to the caller, namelyMyMethodAsync
.MyMethodAsync
prints out"Independent work"
.MyMethodAsync
attempts to assign the result ofLongRunningOperation to
resultbut
awaits it, suspends evaluation of the enclosing
MyMethodAsync, and returns control of the program back to
Main`Main
prints out"Returned to Main"
Task.Delay(1000)
inLongRunningOperationAsync()
completes- A new thread is spawned, In the caller of
LongRunningOperationAsync
(MyMethodAsync
) the integer1
is assigned toresult
. - Evaluation of
MyMethodAsync
completes, andMyMethodAsync
prints out the value ofresult
- Control is given back to
Main
, which suspends evaluation until the user enters a key viaConsole.ReadKey
Firstly, is my understanding of how this program evaluates correct? Secondly, why is it that when I comment Console.ReadKey
, I get the following unexpected result?
Independent work
Returned to Main
Does the Main
method not wait for all threads to get evaluated before exiting out of the program? Why or why not?
CodePudding user response:
The answer to your question "Why or why not?" is complex, but could be answered with a better understanding of a Task
.
A Task
is not a thread. Many tasks can run on a single thread, and a single task can be run on multiple threads.
A task is more like an event, that will trigger a scheduler to run some code on whatever thread it has available at the time (ignoring some complex issues of continuation)
So your question could be re-phrased to "why does my program not listen to all events and block execution until all have fired?". The answer to that question probably kept 1 or 2 designers of the TPL (Tasks) awake at night, and ultimately they decided that the effects of this decision had the potential to do some serious harm to other types of applications
The designers of TPL did give us a way around this (a few editions of C# later) which is async Main methods. In your case it would look like this:
static async Task Main(string[] args)
{
await MyMethodAsync();
Console.WriteLine("Returned to Main");
}