i saw some post regarding Async and Await usage in this site. few people are saying that Async and Await complete its job on separate background thread means spawn a new bac
Need understand two things: a) async/await use tasks(tasks use thread pool) b) async/await is NOT for parallel work.
Just compile this and look at Id's:
static void Main(string[] args)
{
Console.WriteLine("Id main thread is: {0}", Thread.CurrentThread.ManagedThreadId);
TestAsyncAwaitMethods();
Console.WriteLine("Press any key to exit...");
Console.ReadLine();
}
public async static void TestAsyncAwaitMethods()
{
Console.WriteLine("Id thread (void - 0) is: {0}", Thread.CurrentThread.ManagedThreadId);
var _value = await LongRunningMethod();
Console.WriteLine("Id thread (void - 1) is: {0}", Thread.CurrentThread.ManagedThreadId);
}
public static async Task<int> LongRunningMethod()
{
Console.WriteLine("Id thread (int) is: {0}", Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("Starting Long Running method...");
await Task.Delay(1000);
Console.WriteLine("End Long Running method...");
return 1;
}
In effect you are asking, how does a parcel get to my doorstep? By ship or by plane?
The point is that your door step doesn't care wither the parcel was delivered by sea or air.
However the main reason for Microsoft to develop the Task/async/await framework was to take advantage of Event based programming as opposed to Thread based programming.
In general Event based programming is MUCH more efficient and faster than Thread based programming. Which is why most of the .net API uses it. Up until now, however most people avoided Event based programming because it is extremely difficult to understand (again, async/wait was put into place to make this simple).
The simplest solution is,
await LongRunningMethod().wait();
It will cause the main thread to wait (non blocking) till the LongRunningMethod
finishes execution.
The problem is that async/await
is about asynchrony, not threads.
If you use Task.Run
, it will indeed use a background thread (via the Thread Pool, via the Task Parallel Library).
However, for IO operations it relies on IO Completion ports to notify when the operation is complete.
The only guarantee async/await
makes is that when an operation completes, it will return to your caller in the SynchronizationContext that was there when it began. In practical terms, that means it will return on the UI Thread (in a Windows application) or to a thread that can return the HTTP Response (in ASP.NET)
Both of the your statements are probably true, but are confusing.
Async-await does usually complete on a separate background thread but it doesn't mean it starts any separate background thread to complete the job.
The point of these asynchronous operations is to to not hold a thread while an asynchronous operation is being executed because true asynchronous operations do not require a thread.
The parts before that operation can be CPU bound and do require a thread and they are executed by the calling thread. The parts after that operation (which is usually called the completion) also require a thread. If there's a SynchronizationContext
(like there is in UI or asp.net apps) or TaskScheduler
then that part is handled by them. If there isn't any that part is scheduled on the ThreadPool
to be executed by an already existing background thread.
So, in your example Task.Delay
creates a Task
that completes after 5 seconds. During that delay there's no need for a thread so you can use async-await.
The flow of your example is this: The main thread starts executing Main
, calls TestAsyncAwaitMethods
, calls LongRunningMethod
, prints the first message, calls Task.Delay
, registers the rest of the method as a continuation to execute after the Task.Delay
completes, return to Main
, print the message and waits synchronously (blocks) on Console.ReadLine
.
After 5 seconds the timer in Task.Delay
ends and completes the Task
returned from Task.Delay
. The continuation is then scheduled on the ThreadPool
(since it's a console app) and a ThreadPool
thread that was assigned that task prints "End Long Running method...".
In conclusion, a true asynchronous operation doesn't need a thread to be able to run, but it does need a thread after it has completed which is usually a background thread from the ThreadPool
but not necessarily.
Calling await is only possible inside methods marked as async. Once you await a function, the framework knows how to remember your current calling environment and return control to it once the awaited function completes.
You can only ever await functions that return Tasks. So all await deals with is the Task object that gets returned (and until a task is returned, the method you are awaiting is executing synchronously)
To provide you with a Task, the method you are awaiting could spawn a new thread to do it's job, it could synchronously return a completed task with a value (creating a task from a result), it can do whatever it wants. All await does is give the control back to the parent of your function until and unless the Task object you received from the awaitable method is complete. At that point it will continue the execution of your method from the await line.