In this post, I am going to talk about asynchronous programming in Microsoft .NET Framework in the form of questions and answers. It will help the reader with understanding scenarios where to use asynchronous code and how it will benefit application. I would love to hear your comments and questions, so feel free to use the comments area.
Please Note
- This article is not about how to write asynchronous code, you need to use your Google skills for that. I am going to talk about some of the basic concepts of Task based Asynchronous Pattern (TAP) and try to answer questions which come to the developer's mind on his journey to learning asynchronous programming. Well, I had these questions so I found an answer to these and am hoping this would help fellow developers.
- I am talking about asynchronous code execution in CLR and hence, concepts discussed in here need to be seen in that context. For example, when talking about threads, I am referring to managed threads in CLR.
Overview
I am going to give a brief overview of asynchronous programming in .NET and then move on to questions and answers. Support for asynchronous execution has always been there in .NET since the early version of framework. Remember IAsyncResult
interface? Yes, of course, it resulted in too complex code in the first place and then it was a nightmare to maintain it or make changes to it. Even for simplest of functional scenarios, it resulted in too much of code. No wonder, developers dreaded it.
Fast forward to .NET 4 and Microsoft introduced Task, async, and await which greatly simplifies writing asynchronous code. These new constructs made it super easy for the developer to write methods which can spawn a background operation and then later join with its result. All heavy-lifting is shifted to compiler to generate code for making this possible. I must say, it has been one of the best feature additions to .NET based compilers, C# (and I believe VB.NET too), an engineering marvel.
Task based Asynchronous Pattern (TAP) is based on concept of a task, represented by Task type in System.Threading.Tasks
namespace. It represents an asynchronous operation which you could wait for completion, cancel it, or specify a continuation to execute when this asynchronous operation is complete. It provides an object-oriented approach to writing asynchronous code. This frees up the developer from worrying about semantics of language or execution environment for executing asynchronous operation and he can rather focus on functional aspects of application. The core idea here is to enable developer to execute methods on a separate thread seamlessly.
Let's drill deep into this TAP to understand more about it with the help of questions and answers.
Q1. What's the most common use case scenario for asynchronous code?
I am not going to show you a code sample for how to write asynchronous code. Google is your best friend for that. Let's try and understand this with the help of a real-life like scenario:
To give you an analogy, let's consider the case of a restaurant. We all know how it works in a restaurant, waiter takes order and then passes it to chef to prepare and waiter continues with other tasks while chef is preparing food. This is an example of asynchronous execution of tasks in real-life as Waiter is free after passing order to chef and can cater to other customers or serve a completed order to customer and so on. Let's see how it relates to software applications. Your front-end application (waiter) which takes multiple requests (orders) from end users (customers)
can schedule these requests on a background worker (chef) thread. Similar to waiter, while worker thread is executing long running action, your front-end application is free to respond to further user requests. This would be the most common use case scenario for asynchronous code.
First example that you would come across when learning asynchronous code execution in .NET would be a Windows UI application being blocked while executing a long running task, as part of a button click event handler, and then asynchronous code would come to rescue and solve this problem. Task based asynchronous pattern helps to a great extent in case of UI applications.
Biggest pain point solved by asynchronous code, in case of Windows applications, is to do with application responsiveness. Asynchronous code helps you prevent those scary freeze moments (imagine waiter going to kitchen to prepare your order). We've all had that experience many times with Windows XP. Long running tasks can be scheduled on background thread so that main UI thread can respond to user actions in parallel, thereby enabling optimum utilization of processor time and responsive UI.
Q2. Is asynchronous code only for UI applications? How about windows or web services, there is no UI thread in there so is there any benefit of using asynchronous code with these background applications?
Asynchronous code is not only for Windows UI applications, it can help with background applications too. In case of background applications such as Windows or web services, we don't have UI threads but we have I/O threads. Each call to a web service is serviced by an I/O thread in your IIS worker process. If work performed by your web method does not trigger a long running task, you are good but you may have some methods which could take longer to complete. In case of such methods, using asynchronous code to start long running task on a background worker thread (chef) will help free up your I/O thread (waiter) to perform other activities in parallel.
Hence, asynchronous code in background applications helps with optimum utilization of processor time and hence, should be used with Windows and web services too.
Q3. Still unsure with the above answer for how asynchronous code would help in case of a web service. I/O thread would not really be free until worker thread finishes, so in essence, it won't go back to thread pool to serve more requests after invoking long running task but, wait for it to finish. What we are doing is taking work from I/O thread, scheduling it on a worker thread, and then making I/O thread wait for worker thread to finish. Where's the net gain?
It is correct that I/O thread will not be going back to the thread pool until it finishes executing the web method (unless long running task was invoked as fire-and-forget, in which case, it would finish execution of web method and go back to pool). But, it does NOT need to wait while worker thread is executing long running task and that's where you gain with asynchronous code. You can continue executing code on I/O thread in parallel while worker thread is executing long running task. Remember from the earlier restaurant analogy, the waiter does not need to wait for chef to complete an order but can continue in parallel. Hence, gain comes from ability for I/O thread to continue executing in parallel with worker thread. At a certain point though, I/O thread will need result from long running task and it may go into wait mode for worker thread to finish.
Q4. I don't have anything else to execute in parallel while worker thread is executing long running task. Should I still execute long running task asynchronously?
Would you create a restaurant with the assumption that you may not have lot of customers coming in and hence, one person as waiter-cum-chef will do? I am sure no, then why create software like that. Waiter and chef have different roles and responsibilities and hence, you should build these roles separately in your software too.
So yes, it would still make sense to execute long running task asynchronously at least from a design perspective. Don't put yourself into a corner. Also, it does not take lot of effort to write asynchronous code in the first place and hence, Microsoft recommends you to trigger long running activity as an async task.
Q5. Functional requirements of my application require a given (long running) method to be invoked synchronously, will writing it as an async method help?
Yes, it will help. Don't create tight coupling between your implementation and business requirements, which have a high tendency to change frequently and when that happens, you will need to modify your implementation. It is best to keep your long running task method as async and you can always call an asynchronous method synchronously. So, create method performing long running task as async and depending upon your business requirements, you can decide to invoke this method and wait for it to finish.
Q6. Can we invoke an async method synchronously?
Yes, you can invoke an asynchronous method synchronously too. Here's an example:
MyAsyncMethod().Wait();
Q7. Is it required to have multiple processors on system to take advantage of asynchronous code?
Not really, you can benefit from asynchronous code on a machine with single processor too.
Q8. How would asynchronous code execution help on a single processor machine? If there's just a single processor, then it is going to execute any one thread at a time (main or worker), so how does offloading long running task to a separate thread help?
At a logical level, I am sure that restaurant analogy has made it clear to you for how delegating a long running task to a separate worker helps main worker continue in parallel. This question would arise in a developer's mind more from technical perspective to understand how it would work in case of a single processor machine because end of the day, you have a single processor and it would execute one thread at a time, so how would creating multiple threads help. Let's try and understand that.
Processor is a shared resource from perspective of a process. Each process utilizes CPU in a time-sharing manner:
So each process gets a fraction of processor time. Processor executes threads in a process. A process can have multiple threads. Unlike processes, wherein each process gets processor time, not every thread in a process will get executed by processor. Processor will execute “active” threads in a process, ones which are currently executing and it will continue from where it last left off, as it goes around processes.
So within a given process, threads need to efficiently utilize processor time made available to process. A greedy thread who wants to do it all will not help and this is where your application can be smart to spawn another thread where you execute a potentially long running task and provide multiple threads to processor to execute. If main thread in your UI application is executing a long running database query, then it is not the best utilization of processor time because most of the time, this thread would be blocked waiting for response from database server. Hence, if you have multiple threads of execution, then processor time made available for a process can be utilized in optimum manner, by executing other threads which are available and ready for executing instructions. Hence, even when you have a single processor machine, asynchronous code would help with executing in parallel threads.
Q9. If having more threads in a process helps, should I keep that as a goal and create as many threads as possible?
Will increasing number of waiters in your restaurant without increasing chefs in kitchen help? Similarly, increasing threads in the process without increase in processor capacity would not help. Threads are executed by processors and we are limited on number of processors available. Having too little threads may lead to underutilization of processor but, at the same time, creating too many threads would be overkill for the process and rather degrade performance of application.
Q10. What happens when I invoke an asynchronous method? Does it immediately start executing on a separate worker thread of its own?
That depends upon the availability of chef, I'm sorry, processor here as threads are executed by processor. When you start a new task, it is queued by CLR to thread pool and it will be executed as processor executes threads from pool. CLR manages queuing of a task using thread pool extremely well and hence, we don't have to worry about low-level details of scheduling and managing thread pool.
Q11. How do I decide whether a given method needs to be created as async?
Microsoft suggests any method which could potentially take longer than 50ms to complete, is a candidate for being async method. Caller of such method should have an option to invoke it asynchronously.
Q12. Should I consider target hardware for my application or service before writing asynchronous code?
For most cases, no, because CLR manages scheduling of worker threads for you so you don't have to worry about factoring underlying hardware capacity or availability. CLR makes optimum utilization of processor capacity so, leave it for CLR to take care of, it does a good job.
If you have more questions about asynchronous programming, please use the comments area below and I will try to answer them. Thanks.
Happy coding.
Vande Mataram! (A salute to motherland)
P.S. In addition to blogging, I use Twitter to share tips, links, etc. My Twitter handle is: @girishjjain
CodeProject