In my last post, I discussed why asynchronous and parallel programming is becoming increasingly more important. We also saw the difference between asynchronous and parallel programming. In this post we’re going to see when asynchronous programming should be used. I’ll also show you how previous API for asynchronous programming worked. So we can see how the new API make things a lot easier to understand and use. I also going to show you what happens when we use await and discuss the mechanic of async/await.
When Should You Use Asynchronous Programming
We should use asynchronous programming for I/O bound operations. More broadly, we should use it for operations that are outside our control which we can’t have any influence on. For example the time it takes to complete a call to a web service is not something we could control. Other example might be writing to a database or filesystem. In these examples they are going to take the time they need to finish their task and return the result. We could either wait for them and waste a thread in the process. Or we could use that thread for other tasks while those results are getting ready. Other scenarios when using async make sense is for UI programming. When applications that have UI do something in background, the UI thread needs to wait for the operation to complete. But if we use asynchronous programming the UI thread is release to continue its work and the UI remain responsive during long running operations.
Previous Asynchronous API In .Net
Prior to C# 5, building asynchronous program was not as easy as it is now. As you can see in the example above, the Then
method uses the old way of doing this. It’s obvious that the code in Then
method are not as readable as Now
method. The implementation with async
and await
method are more inline with the any normal synchronous code. Also now we can handle exceptions like normal C# code. What the compiler does for us is that when it sees the await keyword, it dispatch the task. It also put the code that comes after the await in ContinueWith block. So by doing this the program structure is preserved. The await keyword also takes care of SynchronizationContext for us and we don’t have to specifically tell the program where it should resume.
What Does async Keyword Actually Do?
Nothing especial really other than telling compiler that await in this code block is a keyword. Take a look at the code below. As you can see I used await as my variable name and it’s perfectly legal. But since there is no async keword in my method signature, the compiler treat it like any other variable name. So it’s here mainly for backward compatibility because maybe someone used the await keyword as an identifier in their program. This means if the keyword await
was in the language when if was first released, the async
keyword would be unnecessary.
What Does await Keyword Actually Do?
Contrary to async
keyword, the await
keyword does a lot. Here’s couple of things it does for us.
- The most important thing it does is that it capture what comes after it, and put it inside continuation block.
- It gives up the thread to its calling code, or if there non, it release the thread back to thread pool.
- If there is a
SynchroniztionContext
it captures it and resume the method back where it first was. - It take the result the operation and assign it to a normal variable, so we don’t have to work with the task but the actual value. One important thing to note here is that await retrieve the value if the operation was successful. If the operation was not successful, it simply returns the exception and raise it. There might be many exception in an operation but it simply returns the first one. By doing this the structure of our code it preserved.
Async And Await Control Flow
It’s important to understand the flow of our program when we encounter await keyword. First thing to note is that, when you await an async
operation, the program does not wait on the current line. Second the await operator is not the same as SomeTask.Result
, the await
keyword release the thread back to the caller whereas the Result block the current thread until the task is finished.
Take a look at the above code sample. After executing the Print
method, what do you think will happen?
Print method calls the SaySomething
method, in the body of SaySomething
I create a simulation of some async task by using Task.Delay
. I awaited the simulated task, at this point the control gets back to the caller which is Print method. Since the value of the result variable is not set yet, the Print
method is going to output empty string to the console. Suppose I await
the SaySomething
method call in Print method too, what you think happens now? Well in that case there’s no other caller to go back to and the thread simply going to be reclaimed by the thread pool. When the simulated task in SaySomething
is finished, the same thread or another thread comes back to the point it left off and execute the rest of the method. If you uncomment the Thread.Sleep
line and comment the Task.Delay
, when the program reach that line, it’s going to block the currently running thread and “Hello world!” output to console.
Summary
This post was an introduction to asynchronous programming in .Net. In this post I discussed when async and await can benefit our application. We also saw the difference between the new and slightly older API for writing asynchronous program in .Net. I also described what async and await keyword does for us and how the control flow of our program changes when using it. You can find the sample codes used in this post in this repository.