Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding async / await in C#

Tags:

c#

async-await

I'm starting to learn about async / await in C# 5.0, and I don't understand it at all. I don't understand how it can be used for parallelism. I've tried the following very basic program:

using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks;  namespace ConsoleApplication1 {     class Program     {         static void Main(string[] args)         {             Task task1 = Task1();             Task task2 = Task2();              Task.WaitAll(task1, task2);              Debug.WriteLine("Finished main method");         }          public static async Task Task1()         {             await new Task(() => Thread.Sleep(TimeSpan.FromSeconds(5)));             Debug.WriteLine("Finished Task1");         }          public static async Task Task2()         {             await new Task(() => Thread.Sleep(TimeSpan.FromSeconds(10)));             Debug.WriteLine("Finished Task2");         }      } } 

This program just blocks on the call to Task.WaitAll() and never finishes, but I am not understanding why. I'm sure I'm just missing something simple or just don't have the right mental model of this, and none of the blogs or MSDN articles that are out there are helping.

like image 550
Alex Marshall Avatar asked Jan 06 '13 00:01

Alex Marshall


People also ask

How do you explain async await?

An async function is a function declared with the async keyword, and the await keyword is permitted within it. The async and await keywords enable asynchronous, promise-based behavior to be written in a cleaner style, avoiding the need to explicitly configure promise chains.

How does async await work internally?

An async function can contain an await expression, that pauses the execution of the function and waits for the passed Promise's resolution, and then resumes the async function's execution and returns the resolved value. You can think of a Promise in JavaScript as the equivalent of Java's Future or C# 's Task.

What is C# await?

The await keyword in C# programming language is used to suspend all async methods enclosed until the point where the operations presented by the asynchronous method are completed. In order or a developer to call multiple functions in an asynchronous way, async and await are highly used and recommended.

When we use async and await in C#?

async/await is single thread event based model. Which allows you to run code out-of-order until the line of code await. In Raku it would actually wait at the await . sub example { my $p = do-something-async; say 'next line'; await $p; say 'done awaiting'}; sub do-something-async { return Promise.in(5).


2 Answers

I recommend you start out with my intro to async/await and follow-up with the official MSDN documentation on TAP.

As I mention in my intro blog post, there are several Task members that are holdovers from the TPL and have no use in pure async code. new Task and Task.Start should be replaced with Task.Run (or TaskFactory.StartNew). Similarly, Thread.Sleep should be replaced with Task.Delay.

Finally, I recommend that you do not use Task.WaitAll; your Console app should just Wait on a single Task which uses Task.WhenAll. With all these changes, your code would look like:

class Program {     static void Main(string[] args)     {         MainAsync().Wait();     }      public static async Task MainAsync()     {         Task task1 = Task1();         Task task2 = Task2();          await Task.WhenAll(task1, task2);          Debug.WriteLine("Finished main method");     }      public static async Task Task1()     {         await Task.Delay(5000);         Debug.WriteLine("Finished Task1");     }      public static async Task Task2()     {         await Task.Delay(10000);         Debug.WriteLine("Finished Task2");     } } 
like image 68
Stephen Cleary Avatar answered Sep 28 '22 20:09

Stephen Cleary


Understand C# Task, async and await

C# Task

Task class is an asynchronous task wrapper. Thread.Sleep(1000) can stop a thread running for 1 second. While Task.Delay(1000) won't stop the current work. See code:

public static void Main(string[] args){     TaskTest(); } private static void TaskTest(){      Task.Delay(5000);      System.Console.WriteLine("task done"); } 

When running," task done" will show up immediately. So I can assume that every method from Task should be asynchronous. If I replace TaskTest () with Task.Run(() =>TaskTest()) task done won't show up at all until I append a Console.ReadLine(); after the Run method.

Internally, Task class represent a thread state In a State Machine. Every state in state machine have several states such as Start, Delay, Cancel, and Stop.

async and await

Now, you may wondering if all Task is asynchronous, what is the purpose of Task.Delay ? next, let's really delay the running thread by using async and await

public static void Main(string[] args){      TaskTest();      System.Console.WriteLine("main thread is not blocked");      Console.ReadLine(); } private static async void TaskTest(){      await Task.Delay(5000);      System.Console.WriteLine("task done"); } 

async tell caller, I am an asynchronous method, don't wait for me. await inside the TaskTest() ask for waiting for the asynchronous task. Now, after running, program will wait 5 seconds to show the task done text.

Cancel a Task

Since Task is a state machine, there must be a way to cancel the task while task is in running.

static CancellationTokenSource tokenSource = new CancellationTokenSource(); public static void Main(string[] args){     TaskTest();     System.Console.WriteLine("main thread is not blocked");     var input=Console.ReadLine();     if(input=="stop"){           tokenSource.Cancel();           System.Console.WriteLine("task stopped");      }      Console.ReadLine(); } private static async void TaskTest(){      try{           await Task.Delay(5000,tokenSource.Token);      }catch(TaskCanceledException e){           //cancel task will throw out a exception, just catch it, do nothing.      }      System.Console.WriteLine("task done"); } 

Now, when the program is in running, you can input "stop" to cancel the Delay task.

like image 33
Andrew Zhu Avatar answered Sep 28 '22 19:09

Andrew Zhu