Consider the following example where the method Compute Averages is going to calculate the average of random numbers generated over the given number. If the method is called with a very large number (100000000), the random number generator takes time to generate the numbers over a very large number of operations and on top of it calculating average for those numbers. The example below shows sequential execution of the method which means if this a windows form application where the application is executed in a single thread, the application becomes unresponsive when this action is carried out and user cannot perform any other action on the form until the action is done.
Tasks
Tasks provide the solution to this problem. Rather than performing the action directly we can start a task to perform the action in background which will then allow us to respond to other user actions. Task provides a means by which a program can partition and dispatch items of work. They are particularly useful when performing actions that may take some time to complete like input/output or network requests. For example, one task can be waiting for a file to be loaded from the disk where the other task can be assembling a message to be sent via network. Below code creates a task which computes average and returns the result. Let us now see how to run these tasks asynchronously using async/await.
Async/Await
Tasks can be hard for the programmers to manage. The application must contain code to create task and start it running and should also contain code by which code performing task can communicate that it has finished running. Exceptions caught while running a task must be caught and passed back to the application. The async and await keywords allow programmers to write code elements that execute asynchronously. The async keyword is used to flag a method as asynchronous. An asynchronous method must contain one or more actions that can be awaited.
An action can be awaited if it returns either a Task or Task that returns a result of a particular type. In the example above AsynComputeAverages returns a Task which returns a double value of the computed average. This method works as a wrapper to ComputeAverages which creates a task and runs the method and returns the result. There is a very good breakfast analogy example demonstrating the use of async/await. Please refer to it if you want to gain more understanding on this topic. Also, when async method is used the control flows like a state diagram from caller to the async method which is very well explained by Microsoft docs.
Below code shows GetAverage method which calls the AsyncComputeAverages method asynchronously. When the method is marked async the compiler treats the method as special. It means the method will have one or more await. The await keyword represents the statement of intent to perform an action. The keyword precedes a call of the method that returns the task to be performed. The compiler will generate code that will cause the async method to return to the caller at the point await is reached. It will go on to generate code that will perform the awaited action asynchronously and continue with the body of the async method.
Exception Handling
One of the other examples where async is frequently used is to fetch webpages form a url. That act of loading web page may fail because the server is offline, or the URL is incorrect. In that event the async method would throw an exception which should be caught by the caller where the await is wrapped with a try/catch block. A thing to note here is we could only catch exception as the FetchWebPage method is returning a string result. It is possible to create async method of type that does not return value. These are to be avoided as there is no way to catch exceptions that they generate.
Awaiting Parallel Tasks
We know that async method can contain many awaited methods. These would all be executed sequentially. However, there is Task.WhenAll method which can be used if you want to create an awaitable task that returns when a number of parallel tasks have completed execution.
Below example shows the task FetchWebPages returns use the FecthWebPage method from the previous example to generate a list of strings containing the text from the given URLs. The Task.WhenAll method is given a list of tasks and return a collection which contains their results when they have completed. The order of items in returned collection may not match the input order of the submitted site names and there is no aggregation of any exceptions thrown by the calls to FecthWebPage. There is also a WhenAny method that will return when any one of the given tasks are complete.
GitHub: Async/Await
#Day1Of100DaysCode
Comments