Why does the await inside the child call actually wait? - c#

Output for the below code is
A
B
C
Since the root call FirstCall() doesn't await, I would have expected the Task.Delay to not actually wait since the Task that is returned by the ChildCall bubbles up and is never waited.
Can someone explain why Task.Delay actually awaits when the root caller is not awaited?
Specifically, when FirstCall reaches the await statement inside it (await ChildCall()) the execution of the method is suspended and control returns to the Main method. Here FirstCall is not awaited - what is preventing it from then going ahead and executing Console.ReadLine()
private static void Main(string[] args)
{
FirstCall();
Console.ReadLine();
}
private static async Task FirstCall()
{
await ChildCall();
Console.WriteLine("C");
}
private static async Task ChildCall()
{
Console.WriteLine("A");
await Task.Delay(TimeSpan.FromSeconds(5));
Console.WriteLine("B");
}

When you don't await, you only continue the thread you are in.
If you write:
private static void Main(string[] args)
{
FirstCall();
Console.WriteLine("D");
Console.ReadLine();
}
Your output will look something like:
D
A
B
C
or
A
D
B
C
Skipping await doesn't disable the other awaits. When calling an async task, you can think of it as creating a new Thread that does it's own thing. When you call await you are simply saying to the current thread, don't do anything until that one is done.
But the second thread can still call await a third thread, and tell itself to await or wait until the third thread is done. The first thread, if not awaited will just continue and close the program before the other threads finish.
You can test this by removing the Console.Readline() and instead write out Main Thread Completed
EDIT: ADDITIONAL
To your specific Quesiton:
Specifically, when FirstCall reaches the await statement inside it (await ChildCall()) the execution of the method is suspended and control returns to the Main method. Here FirstCall is not awaited - what is preventing it from then going ahead and executing Console.ReadLine()
The execution of the method is NOT suspended as you thought. See the example below of your edited code:
private static void Main(string[] args)
{
FirstCall();
Console.WriteLine("Main Thread Finished...");
var word = Console.ReadLine();
Console.WriteLine("Printed: " + word);
Console.ReadLine();
}
In the image below, the left hand side I immediately Typed test. On the right hand side I waited for the child threads to complete:
So to answer your other question:
So you are saying each child method has its own state machine that is honoured irrespective of what its parent is doing?
Partially...
To answer correctly you need to know the difference between a Task and a Thread.
Task vs Thread
In short a Task uses a Thread Pool and a Thread uses a dedicated Thread. Think of a dedicated Thread as starting a secondary Main(args) function. Where as a Thread pool uses a parent-child-treelike structure (Could be wrong on this) to keep track of what threads are executing.
What this means practically
Both Tasks and Threads have complete internal states that is honoured irrespective of what its parent | EXCEPT When the Parent of a Task is completed, all the Children Tasks Stop *Immediately.
Tasks have Return Types where as Threads don't.
For a program to stop - you have to stop all threads but you only have to stop the parent Task to stop the program.

Related

Why does Main not wait for all threads to evaluate in asynchronous program?

#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 calls MyMethodAsync
MyMethodAsync calls LongRunningOperationAsync
LongRunningOperationAsync then calls Task.Delay, but awaits it which suspends further evaluation of the enclosing method LongRunningOperationAsync, returning control to the caller, namely MyMethodAsync.
MyMethodAsync prints out "Independent work".
MyMethodAsync attempts to assign the result of LongRunningOperation to resultbutawaits 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) in LongRunningOperationAsync() completes
A new thread is spawned, In the caller of LongRunningOperationAsync (MyMethodAsync) the integer 1 is assigned to result.
Evaluation of MyMethodAsync completes, and MyMethodAsync prints out the value of result
Control is given back to Main, which suspends evaluation until the user enters a key via Console.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?
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");
}

IO-bound async task not executes asynchronously

I has spend a lot of time to understand async programming principles. But one thing is still unclear. I was confused by this code :
static async Task Method()
{
Console.WriteLine($"Method entered.");
await Task.Delay(1000);
Console.WriteLine($"Await 1 finished.");
await Task.Delay(1000);
Console.WriteLine($"Await 2 finished");
}
static int Main(string[] args)
{
Console.WriteLine($"Main started.");
return AsyncContext.Run(() => MainAsync(args));
}
static async Task<int> MainAsync(string[] args)
{
var t = Method();
Console.WriteLine("Thread starting sleep.");
Thread.Sleep(10000);
Console.WriteLine("Thread stopped sleeping");
Console.WriteLine(t.IsCompleted ? "Method completed" : "Method not completed");
await t;
return 0;
}
Result :
Main started.
Method entered.
Thread starting sleep.
Thread stopped sleeping
Method not completed
Await 1 finished.
Await 2 finished
As I understand while Main thread is sleeping IO-bound operations from Method should be executed (cause Task.Delay emulate IO) and interrupt Main thread sequentially to continue execute Method code.
So I expect to see:
Main started.
Method entered.
Thread starting sleep.
Await 1 finished.
Await 2 finished
Thread stopped sleeping
Method completed
I know that by Thread.Sleep I am making to stop Main thread. But as I understand Method() should not need thread because it consists of IO-bound operations.
Can anybody explain where I am misunderstanding it?
AsynContext that I am using is (here).
By default "await" captures the current synchronization context and spawns the continuation in that original context.
If the context is undefined, continuation is spawned in the default thread pool (TaskScheduler.Default).
I'm not familiar with AsyncContext, but it probably spawns MainAsync under some well synchronization context and since Thread.Sleep blocks the thread that occupies that context, the continuation of "await" will wait until the context is freed.
This is not a strange phenomenon, you can reproduce it without the AsyncContext class. Try to run the same code in a Windows forms application and you will see.
Windows forms have it's own synchronization context that guards against unsynchronized Control manipulation.
To overcome this, you could tell "await" to not capture the synchronization context by using the ConfigureAwait(false) method.
static async Task Method()
{
Console.WriteLine($"Method entered.");
await Task.Delay(1000).ConfigureAwait(false);
Console.WriteLine($"Await 1 finished.");
await Task.Delay(1000).ConfigureAwait(false);
Console.WriteLine($"Await 2 finished");
}
await won't try to spawn continuation in the existing context, rather it would spawn it in a thread pool task.
Why your code is behaving correctly as expected ?
On using the AsyncContext.Run, you are providing an explicit context for Console application which otherwise have NULL Synchronization Context, now when you execute the following lines of code in MainAsync:
var t = Method();
Console.WriteLine("Thread starting sleep.");
Thread.Sleep(10000);
Then Method() starts executing, where on encountering the statement:
await Task.Delay(1000);
It cedes the control back to the caller, where you block the context by making the Thread Sleep for 10s Thread.Sleep(10000);, so now before this sleep is over the Continuation cannot take place in the Async method, since it waits for the Continuation context to be available, moment its free, then it starts executing the Continuation, but by that time it also complete the remaining statements in the MainAsync, which seems to be prioritized and response is as expected, it awaits only in the very end, in fact checking the Task status for any logic like t.IsCompleted is more of a code smell, better is only await t, which waits for the Task completion
There are two ways to get the behavior that you expect
As shown by #Arik, configure both await using ConfigureAwait(false), what does this means, simple that for running the Async continuation it doesn't need the original context and that will continue as true Async operation, hence will provide the result as you expect. Most of the libraries wit Async functions especially IO based, implement ConfigureAwait(false).
Make the call from the Main as return MainAsync(args).Result;, this will ensure standard behavior of the Console applications, which means NULL Synchronization Context, which means Async doesn't care about continuation on any existing Context, it goes on in background even when you are making the Thread sleep, since it doesn't expect that context and the result would be same as you expect
Main started.
Method entered.
Thread starting sleep.
Await 1 finished.
Await 2 finished
Thread stopped sleeping
Method completed
0
AsyncContext schedules all tasks to be executed on a single thread. Your Method consists of Delays and WriteLines. You may think of Delays as analogous to IO operations in that they do not need a thread to be executed on. However, WriteLine requires a thread. Thus, when Method is awaken from Delay it waits for thread be available to execute WriteLine.
Actually the Method would block even if it does not contain WriteLines but only Delays because it needs a thread for the Delay to return to and to start new Delay, but that would be more difficult to notice without WriteLines.

Main Thread terminates before Task thread completion

Hi i need your help guys,
i declared new Task inside my main method like this:
static void Main(string[] args)
{
Task firstTask = Task.Factory.StartNew(()getPackage(packageId));
Task secondTask=firstTask.ContinueWith((_=>UpdatePackage(myPackage)));
}
My problem is, the main thread terminates before my task completes its action.
How should I wait Task to complete its action before terminating the main thread?
Add the following code to make your main thread block until you hit enter in the command window.
Console.Readline();
UPDATE:
If you want a non-interactive solution, then you could just wait for all the tasks to complete.
Task.WaitAll(firstTask, secondTask);
You can use an alternate paradigm for dealing with this.
static void Main(string[] args)
{
MainAsync().Wait();
}
static async Task MainAsync()
{
Task firstTask = new Task(()=>getPackage(packageId));
firstTask.ContinueWith(()=>UpdatePackage(myPackage)));
await firstTask.Run();
}
Be careful with mixing asynchronous and synchronous code like this, but, for your purposes, this should work fine (if this were winforms or WPF, you might have to worry about messaging to the UI thread, but that's not relevant here.
Assign your task to a Thread and then in your main call the .Join() function of the created thread (after it has been started of course). That way the application will wait until the task is over before ending.
This solution is more complexe than a Console.ReadLine but allows you to leave when the ask is over not before and not after.

If an async method is single threaded how can it be run in the background?

I'm trying to understand async/await and have read a number of articles but am still confused about the synchronous/asynchronous nature.
I have the following test console app:
static void Main(string[] args)
{
var test = FooAsync();
Console.WriteLine("After FooAsync");
for (int i = 0; i < 100; i++)
Console.WriteLine("After that");
Console.ReadKey();
}
private static async Task FooAsync()
{
Console.WriteLine("Before delay");
await Task.Delay(1);
Console.WriteLine("After delay");
}
The code gives output along the lines of:
Before delay
After FooAsync
After that
After that
After that
After that
After delay
After that
.
.
I understand that async/await will not create a separate thread for processing and that at the point FooAsync reaches the await Task.Delay(1) line it will return back to Main as the task will not yet have completed, however, as we are only running on a single thread can someone explain what triggers the FooAsync method to resume at some arbitrary point within Main before Main can then continue?
Update
I take it back and i3arnon and dariogriffo are correct. The code does use multiple threads (as I'd have seen before had looked in the debugger or done the obvious as kha suggested). I'd been confused by the Threads section on the following page https://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_Threads not realising that a "continuation" actually refers to a continuation task schedule to run as soon as the task being "awaited" finishes.
This isn't single threaded.
When the delay task completes the rest of the method is posted to the ThreadPool and runs concurrently with your main thread. The "trigger" here is the callback of the internal System.Threading.Timer being used inside Task.Delay.
This behaviour depends on the SynchronizationContext. In a UI environment this would have been posted to the same UI thread and would have to wait until that thread is free.
If you would have been waiting for the task returned from FooAsync then you would only have a single thread running each time.
Async/await may create new threads OR NOT, it depends of the nature of the operation.
If the operation is an IO (for example disks/network operations) probably is coded in a way it will not spin a new thread. You can read from here:
The async and await keywords don't cause additional threads to be created?
If you create your own Async operation and you create a thread, that's a different story, that's why you shouldn't do async over sync
http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx
You can check this also but using Thread.CurrentThread to get the Id of the process. (Add that to a Console.WriteLine)
It's a pretty common misconception that the async or await keywords create new threads. They don't.
The threads are created by running a Task. In this case, the thread is created by the Task.Delay call.

Async/await not reacting as expected

Using the code below I expect the string "Finished" to appear before "Ready" on the console. Could anybody explain to me, why await will not wait for finishing the task in this sample?
static void Main(string[] args)
{
TestAsync();
Console.WriteLine("Ready!");
Console.ReadKey();
}
private async static void TestAsync()
{
await DoSomething();
Console.WriteLine("Finished");
}
private static Task DoSomething()
{
var ret = Task.Run(() =>
{
for (int i = 1; i < 10; i++)
{
Thread.Sleep(100);
}
});
return ret;
}
The reason why you're seeing "Finished" after "Ready!" is because of a common confusion point with async methods, and has nothing to do with SynchronizationContexts. SynchronizationContext control which thread things run on, but 'async' has its own very specific rules about ordering. Otherwise programs would go crazy! :)
'await' ensures that the rest of the code in the current async method doesn't execute until after the thing awaited completes. It doesn't promise anything about the caller.
Your async method returns 'void', which is intended for async methods that don't allow for the original caller to rely on method completion. If you want your caller to also wait, you'll need to make sure your async method returns a Task (in case you only want completion/exceptions observed), or a Task<T> if you actually want to return a value as well. If you declare the return type of the method to be either of those two, then the compiler will take care of the rest, about generating a task that represents that method invocation.
For example:
static void Main(string[] args)
{
Console.WriteLine("A");
// in .NET, Main() must be 'void', and the program terminates after
// Main() returns. Thus we have to do an old fashioned Wait() here.
OuterAsync().Wait();
Console.WriteLine("K");
Console.ReadKey();
}
static async Task OuterAsync()
{
Console.WriteLine("B");
await MiddleAsync();
Console.WriteLine("J");
}
static async Task MiddleAsync()
{
Console.WriteLine("C");
await InnerAsync();
Console.WriteLine("I");
}
static async Task InnerAsync()
{
Console.WriteLine("D");
await DoSomething();
Console.WriteLine("H");
}
private static Task DoSomething()
{
Console.WriteLine("E");
return Task.Run(() =>
{
Console.WriteLine("F");
for (int i = 1; i < 10; i++)
{
Thread.Sleep(100);
}
Console.WriteLine("G");
});
}
In the above code, "A" through "K" will print out in order. Here's what's going on:
"A": Before anything else gets called
"B": OuterAsync() is being called, Main() is still waiting.
"C": MiddleAsync() is being called, OuterAsync() is still waiting to see if MiddleAsync() is complete or not.
"D": InnerAsync() is being called, MiddleAsync() is still waiting to see if InnerAsync() is complete or not.
"E": DoSomething() is being called, InnerAsync() is still waiting to see if DoSomething() is complete or not. It immediately returns a task, which starts in parallel.
Because of parallelism, there is a race between InnerAsync() finishing its test for completeness on the task returned by DoSomething(), and the DoSomething() task actually starting.
Once DoSomething() starts, it prints out "F", then sleeps for a second.
In the meanwhile, unless thread scheduling is super messed up, InnerAsync() almost certainly has now realized that DoSomething() is not yet complete. Now the async magic starts.
InnerAsync() yanks itself off the callstack, and says that its task is incomplete.
This causes MiddleAsync() to yank itself off the callstack and say that its own task is incomplete.
This causes OuterAsync() to yank itself off the callstack, and say that its task is incomplete as well.
The task is returned to Main() which notices it's incomplete, and the Wait() call begins.
meanwhile...
On that parallel thread, the old-style TPL Task created in DoSomething() eventually finishes sleeping. It prints out "G".
Once that task gets marked as complete, the rest of InnerAsync() gets scheduled on the TPL to get executed again, and it prints out "H". That completes the task originally returned by InnerAsync().
Once that task gets marked complete, the rest of MiddleAsync() gets scheduled on the TPL to get executed again, and it prints out "I". That completes the task originally returned by MiddleAsync().
Once that task gets marked complete, the rest of OuterAsync() gets scheduled on the TPL to get executed again, and it prints out "J". That completes the task originally returned by OuterAsync().
Since OuterAsync()'s task is now complete, the Wait() call returns, and Main() prints out "K".
Thus even with a little bit of parallelism in the order, C# 5 async still guarantees that the console writing occurs in that exact order.
Let me know if this still seems confusing :)
You're in a console app, so you don't have a specialized SynchronizationContext, which means your continuations will run on Thread Pool threads.
Also, you are not awaiting the call to TestAsync() in Main. This means that when you execute this line:
await DoSomething();
the TestAsync method returns control to Main, which just continues executing normally - i.e. it outputs "Ready!" and waits for a key press.
Meanwhile, a second later when DoSomething completes, the await in TestAsync will continue on a thread pool thread and outputs "Finished".
As others have noted, console programs use the default SynchronizationContext, so the continuations created by await get scheduled to the thread pool.
You can use AsyncContext from my Nito.AsyncEx library to provide a simple async context:
static void Main(string[] args)
{
Nito.AsyncEx.AsyncContext.Run(TestAsync);
Console.WriteLine("Ready!");
Console.ReadKey();
}
Also see this related question.

Categories

Resources