The code we want to run asynchronously could either be CPU-bound or IO-bound. CPU-bound code keeps the CPU busy, requiring intensive processing, calculations etc. On the other hand, IO-bound code frees up the CPU while waiting for an IO operation to complete, for instance, get some data from a web service. Both kinds of asynchronous methods are illustrated below.
Creating Asynchronous method
CPU-bound Async method
public async Task<string> OurMethodAsync() { string x = await Task.Run(() => { // performs CPU intensive work return LongRunningTask(); }); return x; }
Above method doesn’t do anything special. Rather than performing the work itself, it creates a thread and delegates the work to it. It will not make the task run faster, in fact, it may take more time due to multi-threading overhead. One reason to do things this way is to free the calling thread and not keep it busy for long time. This is required in case of User Interface threads, for instance.
IO-Bound Async method
For IO operation such as working with file system, requests to web servers etc., .Net framework already provides us with methods which run asynchronously. These methods uses lower levels OS calls to provide asynchronous behavior for blocking IO operations.
Below is our asynchronous method which uses .Net Framework’s WebClient.DownloadStringTaskAsync method.
public async Task<string> GetWebPage(string url) { var webClient = new WebClient(); string txt = await webClient.DownloadStringTaskAsync(url); return txt; }
Consuming asynchronous method
Consuming asynchronous method with await
private async void button1_Click(object sender, EventArgs e) { textBox1.Text = await GetWebPage("http://www.yahoo.com"); }
This button click event consumes the IO-bound async method defined above. If GetWebPage method is taking a long time, the control will return back to the caller method. Once results of GetWebPage are available, execution will start again with the instruction after await keyword. This will ensure that the event does not block the UI thread.
Calling asynchronous methods concurrently
We can also use asynchronous method to run tasks in parallel.
private async void button1_Click(object sender, EventArgs e) { Task<string> task1 = GetWebPage("http://www.yahoo.com"); Task<string> task2 = GetWebPage("http://www.google.com"); await Task.WhenAll(task1, task2); textBox1.Text = task1.Result; textBox2.Text = task2.Result; }
Notice we are not using await keyword now when invoking GetWebPage method. This causes the return type to change also, we are expecting Task
The flow control is also very different. If GetWebPage is blocking, the control doesn’t return to the caller method, rather execution continues to the next statement in the event.
We have await in the third line which will relinquish control to the caller method if task1 or task2 are not completed yet. When the result of the two tasks are available the last two lines of code are executed on the UI thread.