I am really curious how async/await enables your program not to be halted.
I really like the way how Stephen Cleary explains async/await: "I like to think of "await" as an "asynchronous wait". That is to say, the async method pauses until the awaitable is complete(so it waits), but the actual thread is not blocked (so it's asynchornous)."
I've read that async method works synchronously till compilator meets await keywords. Well. If compilator cannot figure out awaitable, then compilator queues the awaitable and yield control to the method that called method AccessTheWebAsync. OK.
Inside the caller (the event handler in this example), the processing pattern continues. The caller might do other work that doesn't depend on the result from AccessTheWebAsync before awaiting that result, or the caller might await immediately. The event handler is waiting for AccessTheWebAsync, and AccessTheWebAsync is waiting for GetStringAsync. Let's see an msdn example:
async Task<int> AccessTheWebAsync()
{
// You need to add a reference to System.Net.Http to declare client.
HttpClient client = new HttpClient();
// GetStringAsync returns a Task<string>. That means that when you await the
// task you'll get a string (urlContents).
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
// You can do work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork();
// The await operator suspends AccessTheWebAsync.
// - AccessTheWebAsync can't continue until getStringTask is complete.
// - Meanwhile, control returns to the caller of AccessTheWebAsync.
// - Control resumes here when getStringTask is complete.
// - The await operator then retrieves the string result from getStringTask.
string urlContents = await getStringTask;
// The return statement specifies an integer result.
// Any methods that are awaiting AccessTheWebAsync retrieve the length value.
return urlContents.Length;
}
Another article from msdn blog says that async/await does not create new thread or use other threads from thread pool. OK.
My questions:
Where does async/await execute awaitable code(in our example downloading a web site) cause control yields to the next row of code of our program and program just asks result of Task<string> getStringTask? We know that no new threads, no thread pool are not used.
Am I right in my silly assumption that CLR just switches the current executable code and awaitable part of the method between each other in scope of one thread? But changing the order of addends does not change the sum and UI might be blocked for some unnoticeable time.
Where does async/await execute awaitable code(in our example downloading a web site) cause control yields to the next row of code of our program and program just asks result of Task getStringTask? We know that no new threads, no thread pool are not used.
If the operation is truly asynchronous, then there's no code to "execute". You can think of it as all being handled via callbacks; the HTTP request is sent (synchronously) and then the HttpClient registers a callback that will complete the Task<string>. When the download completes, the callback is invoked, completing the task. It's a bit more complex than this, but that's the general idea.
I have a blog post that goes into more detail on how asynchronous operations can be threadless.
Am I right in my silly assumption that CLR just switches the current executable code and awaitable part of the method between each other in scope of one thread?
That's a partially true mental model, but it's incomplete. For one thing, when an async method resumes, its (former) call stack is not resumed along with it. So async/await are very different than fibers or co-routines, even though they can be used to accomplish similar things.
Instead of thinking of await as "switch to other code", think of it as "return an incomplete task". If the calling method also calls await, then it also returns an incomplete task, etc. Eventually, you'll either return an incomplete task to a framework (e.g., ASP.NET MVC/WebAPI/SignalR, or a unit test runner); or you'll have an async void method (e.g., UI event handler).
While the operation is in progress, you end up with a "stack" of task objects. Not a real stack, just a dependency tree. Each async method is represented by a task instance, and they're all waiting for that asynchronous operation to complete.
Where is continuation of awaitable part of method performed?
When awaiting a task, await will - by default - resume its async method on a captured context. This context is SynchronizationContext.Current unless it is null, in which case it is TaskScheduler.Current. In practice, this means that an async method running on a UI thread will resume on that UI thread; an async method handling an ASP.NET request will resume handling that same ASP.NET request (possibly on a different thread); and in most other cases the async method will resume on a thread pool thread.
In the example code for your question, GetStringAsync will return an incomplete task. When the download completes, that task will complete. So, when AccessTheWebAsync calls await on that download task, (assuming the download hasn't already finished) it will capture its current context and then return an incomplete task from AccessTheWebAsync.
When the download task completes, the continuation of AccessTheWebAsync will be scheduled to that context (UI thread, ASP.NET request, thread pool, ...), and it will extract the Length of the result while executing in that context. When the AccessTheWebAsync method returns, it sets the result of the task previously returned from AccessTheWebAsync. This in turn will resume the next method, etc.
In general the continuation (the part of your method after await) can run anywhere. In practice it tends to run on the UI thread (e.g. in a Windows application) or on the thread pool (e.g. in an ASP .NET server). It can also run synchronously on the caller thread in some cases ... really it depends on what kind of API you're calling and what synchronization context is being used.
The blog article you linked does not say that continuations are not run on thread pool threads, it merely says that marking a method as async does not magically cause invocations of the method to run on a separate thread or on the thread pool.
That is, they're just trying to tell you that if you have a method void Foo() { Console.WriteLine(); }, changing that to async Task Foo() { Console.WriteLine(); } doesn't suddenly cause an invocation of Foo(); to behave any differently at all – it'll still be executed synchronously.
If by "awaitable code" you mean the actual asynchronous operation, then you need to realize that it "executes" outside of the CPU so there's no thread needed and no code to run.
For example when you download a web page, most of the operation happens when your server sends and receives data from the web server. There's no code to execute while this happens. That's the reason you can "take over" the thread and do other stuff (other CPU operations) before awaiting the Task to get the actual result.
So to your questions:
It "executes" outside of the CPU (so it's not really executed). That could mean the network driver, a remote server, etc. (mostly I/O).
No. Truly asynchronous operations don't need to be executed by the CLR. They are only started and completed in the future.
A simple example is Task.Delay which creates a task that completes after an interval:
var delay = Task.Delay(TimeSpan.FromSeconds(30));
// do stuff
await delay;
Task.Delay internally creates and sets a System.Threading.Timer that will execute a callback after the interval and complete the task. System.Threading.Timer doesn't need a thread, it uses the system clock. So you have "awaitable code" that "executes" for 30 seconds but nothing actually happens in that time. The operation started and will complete 30 seconds in the future.
Related
My company has a Nuget Package they wrote that can do various common tasks easily for you. One of which is making HTTP requests. Normally I always make my HTTP requests asynchronous, however in this Nuget package is the following code:
protected T GetRequest<T>(string requestUri)
{
// Call the async method within a task to run it synchronously
return Task.Run(() => GetRequestAsync<T>(requestUri)).Result;
}
Which calls this function:
protected async Task<T> GetRequestAsync<T>(string requestUri)
{
// Set up the uri and the client
string uri = ParseUri(requestUri);
var client = ConfigureClient();
// Call the web api
var response = await client.GetAsync(uri);
// Process the response
return await ProcessResponse<T>(response);
}
My question is, is this code really running synchronously by just wrapping the GetRequestAsync(requestUri) inside a Task.Run and calling .Result on the returned task? This seems like a deadlock waiting to happen, and we are seeing issues in areas of our app that utilize this function when running at higher loads.
Accessing Task.Result will block the current thread until the Task is complete, so it is not asynchronous.
As for deadlocks, this shouldn't happen, as Task.Run uses another thread for GetRequestAsync, which is not being blocked by the call to Result.
The reason that will not cause a deadlock is because Task.Run will push the delegate to be executed in a threadpool thread. Threadpool threads has no SynchronizationContext therefore no deadlock happens as there is no sync context to lock on between the async method GetRequestAsync and the caller. Same as you could have called .Result directly on the actual async method as well within Task.Run() block and that would not have caused a deadlock either.
Very inefficient though as you freeze 1 thread ie. 1 Core in the CPU do nothing but wait for the async method and I/O calls within it to complete. That s probably why you see a freeze in high load scenarios.
If you have a sync/async deadlock issue due to capturing sync context and blocking on async call, the deadlock will happen irrespective of load on a single call..
This won't cause a deadlock. But it's surely a resources wasting as one of the threads may be blocked.
The deadlock though may be possible if GetRequest looked like this:
protected T GetRequest<T>(string requestUri)
{
var task = GetRequestAsync<T>(requestUri);
return task.Result;
// or
// return GetRequestAsync<T>(requestUri).Result;
}
In example above you can see that I call GetRequestAsync within the current thread. Let's give the thread a number 0. Consider this line from the GetRequestAsync - await client.GetAsync(uri). .GetAsync is executed by a thread 1. After .GetAsync is done, default task scheduler is trying to return execution flow to the thread that executed the line - to the thread 0. But the thread that executed the line (0) is blocked right now as after we executed GetRequestAsync(), we are blocking it (thread 0) with task.Result. Hence our thread 0 remains blocked as it cannot proceed with execution of GetRequestAsync after await client.GetAsync(uri) is done nor it can give us the Result.
It's a pretty common mistake and I suppose you meant this one when asked about the deadlock. Your code is not causing it because you are executing GetRequestAsync from within another thread.
The C# compiler already warns us if we have a method that has the async modifier but does not use the await operator.
According to this answer there's no point adding an await to the end of an async method (and in that case, just remove the async modifier).
But what if the method has an expensive synchronous operation it needs to perform before calling a subsequent true async method?
For example, if I'm using HttpClient:
private readonly HttpClient client = ...
public Task<HttpResponseMessage> CallMyWebServiceMethod() {
HttpRequestMessage request = this.SomeExpensiveButSynchronousMethod();
return this.client.SendAsync( request );
}
This code would block the caller (due to SomeExpensiveButSynchronousMethod).
However, if I change the code to this:
public async Task<HttpResponseMessage> CallMyWebServiceMethod() {
HttpRequestMessage request = this.SomeExpensiveButSynchronousMethod();
return await this.client.SendAsync( request );
}
and I call it like so:
HttpResponse response = await myWrapper.CallMyWebServiceMethod();
...I understand the TPL would spin up a background thread immediately and then run CallMyWebServiceMethod in the background thread, resuming whatever the parent code wants, making the entire call non-blocking in the process, before resuming after the Task completes and returns the HttpResponse.
...if that's the case then it seems contradictory.
If I'm wrong, and the call is blocking until it gets to SendAsync then how can I execute SomeExpensiveButSynchronousMethod on the same background thread as the HttpClient uses for its request?
According to this answer there's no point adding an await to the end of an async method (and in that case, just remove the async modifier).
That's an oversimplification. See my blog post on eliding async and await.
But what if the method has an expensive synchronous operation it needs to perform before calling a subsequent true async method?
This is a rare case, but the appropriate solution IMO is to execute the synchronous operation synchronously (i.e., not wrapped in a Task.Run) and be sure to document its behavior.
I understand the TPL would spin up a background thread immediately and then run CallMyWebServiceMethod in the background thread, resuming whatever the parent code wants, making the entire call non-blocking in the process, before resuming after the Task completes and returns the HttpResponse.
That is not at all what happens. You may find my async intro helpful. Quote:
The beginning of an async method is executed just like any other method. That is, it runs synchronously until it hits an “await” (or throws an exception).
In actuality, both of your examples synchronously block the caller while executing SomeExpensiveButSynchronousMethod.
If I'm wrong, and the call is blocking until it gets to SendAsync then how can I execute SomeExpensiveButSynchronousMethod on the same background thread as the HttpClient uses for its request?
HttpClient doesn't use a background thread for its request, so this part of the question doesn't make sense. For more information on how asynchronous I/O works, see my blog post There Is No Thread.
To answer the actual question:
Should I add the async modifier if I return a Task in an expensive method?
Yes. But the reason you should do so is not to "make it asynchronous"; it's so that any exceptions from SomeExpensiveButSynchronousMethod are captured and placed on the returned Task, which is the expected semantic for methods that follow the Task-based Asynchronous Pattern (TAP).
I understand the TPL would spin up a background thread immediately and then run CallMyWebServiceMethod
No, that's not what happens. The first synchronous part of an async method executes synchronously. If you want make sure it does not block the current thread, you should use Task.Run().
Your expensive method is going to block the caller either way. async doesn't magically create threads for you, that's what Task does (sometimes). So, if you add async and await the SendAsync, you're just adding state-machine overhead needlessly.
see also http://blog.stephencleary.com/2016/12/eliding-async-await.html
I try to understand why is better using the 'Async' method than using simple old synchronous way.
There is small issue that I don't understand.
On the synchronous way:
I have some thread that call method FileStream.Read(...).
Because calling this method is synchronous so the calling thread will wait until the IRP (I/O request packet) will signal that this Io request is finish.
Until the IRP will return ==> this thread will suspend ( sleep ).
On the A-synchronous way:
I have some thread (Task .. lets call this thread 'TheadAsync01') that calls method FileStream.ReadAsync(...).
Because calling this method is A-Synchronous so the calling thread will not wait until the IRP (I/O request packet) will signal that this IO request is finish; and this calling thread will continue to his next action.
Now, When the IRP will signal that this IO request is finish what happened?
(The thread TheadAsync01 is now doing something else and can't continue the work with what the 'FileStream.ReadAsync' return now.)
Is other thread will continue the continue the next action with the return value of the ReadAsync?
What I don't understand here?
The reason it bothers you is this mistaken assumption:
The thread TheadAsync01 is now doing something else and can't continue
the work with what the 'FileStream.ReadAsync' return now.
In a typical application I/O is by far the most time-consuming task.
When TPL is used correctly, threads are not blocked by time-consuming operations. Instead, everything time-consuming (in other words, any I/O) is delegated via await. So when your IRP signals, the thread will either be free from work, or will be free very soon.
If there's some heavy calculation (something time-consuming which is not I/O), you need to plan accordingly, for example run it on a dedicated thread.
The function ReadAsync immediately returns a value, namely a Task object. Somewhere you should do something with the return value. The canonical way is to use await:
await FileStream.ReadAsync(...)
This will ensure that the calling site will not continue with operation until ReadAsync has completed its job. If you want to do something in the meantime you could await the task object later or you can manually deal with the task object.
If you just call ReadAsync, ignoring the returned task object, doing nothing with it, then your reading is mostly an expensive no-op.
When a ***Async method returns a Task or Task you use this to track the running of the asynchronous operation. You can make the call behave synchronously with respect to the calling code by calling .Wait() on the task. Alternatively, as of .Net 4.5 you can await the task.
e.g:
private async void DoFileRead(...)
{
var result = await fileStream.ReadAsync(...);
// Do follow on tasks
}
In this scenario any follow on code would be wrapped in a continuation by the compiler and executed when the async call completed. One requirement of using the async keyword is to mark the calling method with the async keyword (see the example above).
I already know that async-await keeps the thread context , also handle exception forwarding etc.(which helps a lot).
But consider the following example :
/*1*/ public async Task<int> ExampleMethodAsync()
/*2*/ {
/*3*/ var httpClient = new HttpClient();
/*4*/
/*5*/ //start async task...
/*6*/ Task<string> contentsTask = httpClient.GetStringAsync("http://msdn.microsoft.com");
/*7*/
/*8*/ //wait and return...
/*9*/ string contents = await contentsTask;
/*10*/
/*11*/ //get the length...
/*12*/ int exampleInt = contents.Length;
/*13*/
/*14*/ //return the length...
/*15*/ return exampleInt;
/*16*/ }
If the async method (httpClient.GetStringAsync) is an IO operation ( like in my sample above) So - I gain these things :
Caller Thread is not blocked
Worker thread is released because there is an IO operation ( IO completion ports...) (GetStringAsync uses TaskCompletionSource and not open a new thread)
Preserved thread context
Exception is thrown back
But What if instead of httpClient.GetStringAsync (IO operation) , I have a Task of CalcFirstMillionsDigitsOf_PI_Async (heavy compute bound operation on a sperate thread)
It seems that the only things I gain here is :
Preserved thread context
Exception is thrown back
Caller Thread is not blocked
But I still have another thread ( parallel thread) which executes the operation. and the cpu is switching between the main thread and the operation .
Does my diagnostics is correct?
Actually, you only get the second set of advantages in both cases. await doesn't start asynchronous execution of anything, it's simply a keyword to the compiler to generate code for handling completion, context etc.
You can find a better explanation of this in '"Invoke the method with await"... ugh!' by Stephen Toub.
It's up to the asynchronous method itself to decide how it achieves the asynchronous execution:
Some methods will use a Task to run their code on a ThreadPool thread,
Some will use some IO-completion mechanism. There is even a special ThreadPool for that, which you can use with Tasks with a custom TaskScheduler
Some will wrap a TaskCompletionSource over another mechanism like events or callbacks.
In every case, it is the specific implementation that releases the thread (if one is used). The TaskScheduler releases the thread automatically when a Task finishes execution, so you get this functionality for cases #1 and #2 anyway.
What happens in case #3 for callbacks, depends on how the callback is made. Most of the time the callback is made on a thread managed by some external library. In this case you have to quickly process the callback and return to allow the library to reuse the method.
EDIT
Using a decompiler, it's possible to see that GetStringAsync uses the third option: It creates a TaskCompletionSource that gets signalled when the operation finishes. Executing the operation is delegated to an HttpMessageHandler.
Your analysis is correct, though the wording on your second part makes it sound like async is creating a worker thread for you, which it is not.
In library code, you actually want to keep your synchronous methods synchronous. If you want to consume a synchronous method asynchronously (e.g., from a UI thread), then call it using await Task.Run(..)
Yes, you're correct. I cannot find any wrong statement in your question. Just the term "Preserved thread context" is unclear to me. Do you mean the "logical control flow"? In that case I'd agree.
Regarding the CPU bound example: you'd normally not do it that way because starting a CPU-based task and waiting for it increases overhead and decreases throughput. But this might be valid if you need the caller to be unblocked (in the case of a WinForms or WFP project for example).
I was reading http://msdn.microsoft.com/en-US/library/vstudio/hh191443.aspx.
Example code:
async Task<int> AccessTheWebAsync()
{
// You need to add a reference to System.Net.Http to declare client.
HttpClient client = new HttpClient();
// GetStringAsync returns a Task<string>. That means that when you await the
// task you'll get a string (urlContents).
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
// You can do work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork();
// The await operator suspends AccessTheWebAsync.
// - AccessTheWebAsync can't continue until getStringTask is complete.
// - Meanwhile, control returns to the caller of AccessTheWebAsync.
// - Control resumes here when getStringTask is complete.
// - The await operator then retrieves the string result from getStringTask.
string urlContents = await getStringTask;
// The return statement specifies an integer result.
// Any methods that are awaiting AccessTheWebAsync retrieve the length value.
return urlContents.Length;
}
The page also says:
The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread
Does this "no additional thread is created" applies within scope of the method marked as async?
I would imagine in order for both GetStringAsync and AccessTheWebAsync to be running at the same time (otherwise GetStringAsync will never finish as AccessTheWebAsync has control now), eventually GetStringAsync has to run on a different thread from AccessTheWebAsync's thread.
To me, writing async method is only useful at not adding more thread when the method it awaits is also async (which already use extra thread to do its own thing in parallel)
Is my understanding correct?
This is the key to the power of async. GetStringAsync and other naturally-asynchronous operations do not require a thread. GetStringAsync just sends out the HTTP request and registers a callback to run when the server replies. There's no need for a thread just to wait for the server to respond.
In reality, the thread pool is used just a tiny bit. In the example above, the callback registered by GetStringAsync will execute on a thread pool thread, but all it does is notify AccessTheWebAsync that it can continue executing.
I have an async intro blog post you may find helpful.
I would imagine in order for both GetStringAsync and AccessTheWebAsync to be running at the same time ...
They don't run at the same time (at least not in the way you're thinking). Now, if HttpClient.GetStringAsync itself
started work on a different thread, then that code could be running at the same time, -or-
Had an await (with ConfigureAwait(false)), then the remainder of the work in that method would be scheduled on to the Thread pool thread (and so that code could be running at the same time.
The point is that declaring a method as async and/or using await, doesn't cause the method that that you are authoring to be run on a separate thread (you would have to do that explicitly).
Note:
Without having the code (or documentation) of another asynchronous method, you don't really know how much of it is run synchronously. It doesn't really start being asynchronous until that method does an await or explicitly starts work on another thread (usually by starting a new Task)
There is a thread that is taken from the thread pool for the operation if that is necessary. In case of a console (not discussing the UI thread or IO threads) the current thread goes in the console and another thread is taken for the execution, and this new thread is the one that executes the remaining of the operation.
What the author is saying here, is that simply using the async and await keywords somewhere does not cause the current method to run on a different thread. Let's investigate what happens in the code provided.
async Task<int> AccessTheWebAsync()
{
// You need to add a reference to System.Net.Http to declare client.
HttpClient client = new HttpClient();
// GetStringAsync returns a Task<string>. That means that when you await the
// task you'll get a string (urlContents).
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
Everything up to this point has executed in a single thread. At this point, the client.GetStringAsync call could spin off a new thread (although this is not guarenteed for any async method). It should be noted though that the GetStringAsync method essentially starts up on this current thread (such as actually making the call), but reading the response will execute in a different thread once it has returned. This is represented by it returning a Task object. The Task may represent an already completed bit of work, a currently executing secondary thread, or a unit of work that is simply scheduled to execute later.
DoIndependentWork();
This now executes on our primary thread, after the call has been queued (or possibly sent). Thus, this could be occuring while waiting for the request to be returned. Note that we are still on our primary thread.
string urlContents = await getStringTask;
At this point, our thread returns. .NET will create a continuation function containing the remainder of the method (return urlContents.Length;) which will automatically be called for us once the getStringTask completes on it's own thread. At that point, a new thread will pick up the continuation.
Through all of this, the entirety of what we wrote in our async method, up to the await keyword, ran in a single thread. Sure, we called another method that could happen to spawn another thread, but there was nothing that we did to create another thread just by using the async/await keywords. The continuation at the end can be called possibly by a different thread, but after our initial function has actually returned (Which is why our function returns a Task object, to represent work that may not have yet completed when any calls to this function returns).