await/async is.NetFramework 4.5, grammatical sugar, functionality provided by the compiler!
await/async is a C#reserved keyword, usually paired, and the general recommendation is either not to be used or to the end
- The async modifier, which can appear alone, is meaningless and has warnings
- Await is in the method body and can only appear before task/async methods, only await will error
Here's a code to dissect the usage of async and await.
One: Only one async has no await


1 /// <summary> 2 /// only async No, await,There will be one warn 3 /// No difference from the normal method 4 /// </summary> 5 private static async void NoReturnNoAwait() 6 { 7 //Main thread execution 8 Console.WriteLine($"NoReturnNoAwait Sleep before Task,ThreadId={Thread.CurrentThread.ManagedThreadId}"); 9 Task task = Task.Run(() =>//Start a new thread to complete the task 10 { 11 Console.WriteLine($"NoReturnNoAwait Sleep before,ThreadId={Thread.CurrentThread.ManagedThreadId}"); 12 Thread.Sleep(3000); 13 Console.WriteLine($"NoReturnNoAwait Sleep after,ThreadId={Thread.CurrentThread.ManagedThreadId}"); 14 }); 15 16 //Main thread execution 17 Console.WriteLine($"NoReturnNoAwait Sleep after Task,ThreadId={Thread.CurrentThread.ManagedThreadId}"); 18 }
The call is as follows:


1 private async static Task Test() 2 { 3 Console.WriteLine($"start Current Main Thread id={Thread.CurrentThread.ManagedThreadId.ToString("00")}"); 4 { 5 NoReturnNoAwait(); 6 } 7 Console.WriteLine($"end Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); 8 Console.Read(); 9 }
The results are as follows:
If async is not used, this is equivalent to a normal method, and note that the return value of the method is received using Task, so it does not need to return directly
Two: there are async and await methods


1 /// <summary> 2 /// async/await 3 /// Not alone await 4 /// await Can only be placed in task Front 5 /// Not recommended void Return value, using Task To replace 6 /// Task and Task<T>Ability to use await, Task.WhenAny, Task.WhenAll And so on. Async Void No way 7 /// </summary> 8 private static async Task NoReturn() 9 { 10 //Main thread execution 11 Console.WriteLine($"NoReturn Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}"); 12 TaskFactory taskFactory = new TaskFactory(); 13 Task task = taskFactory.StartNew(() => 14 { 15 Console.WriteLine($"NoReturn Sleep before,ThreadId={Thread.CurrentThread.ManagedThreadId}"); 16 Thread.Sleep(6000); 17 Console.WriteLine($"NoReturn Sleep after,ThreadId={Thread.CurrentThread.ManagedThreadId}"); 18 }); 19 20 await task;//The main thread returns here to perform the main thread task 21 Console.WriteLine($"NoReturn Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}"); 22 23 //Notice above 24 // await task; 25 // Console.WriteLine($"NoReturn Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}"); 26 //Equivalent to the following code 27 //task.ContinueWith(t => 28 //{ 29 // Console.WriteLine($"NoReturn Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}"); 30 //}); 31 }
The call is as follows:


1 private async static Task Test() 2 { 3 Console.WriteLine($"start Current Main Thread id={Thread.CurrentThread.ManagedThreadId.ToString("00")}"); 4 { 5 NoReturn(); 6 for (int i = 0; i < 5; i++) 7 { 8 Thread.Sleep(3000); 9 Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")} i={i}"); 10 } 11 } 12 Console.WriteLine($"end Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); 13 Console.Read(); 14 }
The results are as follows:
As you can see from the above results:
1: The main thread calls the async/await method, and the main thread encounters await and returns to perform subsequent actions.
2:The code behind await waits for the task to finish before continuing, which is like wrapping the code behind await into a callback action for continue
3: The callback action may then be a Task thread, a new child thread, or a main thread
3: Tasks with return values must have t.Result if they are to be returned


1 /// <summary> 2 /// With return value Task 3 /// To use the return value, you must wait for the subthread to finish calculating 4 /// </summary> 5 /// <returns>async Only return long</returns> 6 private static async Task<long> SumAsync() 7 { 8 Console.WriteLine($"SumAsync 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); 9 long result = 0; 10 11 await Task.Run(() => 12 { 13 for (int k = 0; k <3; k++) 14 { 15 Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); 16 Thread.Sleep(1000); 17 } 18 for (long i = 0; i < 999999999; i++) 19 { 20 result += i; 21 } 22 }); 23 24 Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); 25 await Task.Run(() => 26 { 27 for (int k = 0; k <3; k++) 28 { 29 Console.WriteLine($"SumAsync11111 {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); 30 Thread.Sleep(1000); 31 } 32 for (long i = 0; i < 999999999; i++) 33 { 34 result += i; 35 } 36 }); 37 Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); 38 39 return result; 40 }
The call is as follows:


1 private async static Task Test() 2 { 3 Console.WriteLine($"start Current Main Thread id={Thread.CurrentThread.ManagedThreadId.ToString("00")}"); 4 { 5 Task<long> t = SumAsync(); 6 Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); 7 long result = t.Result;//Visit result Main Thread Waiting Task Completion is equivalent to t.Wait(); 8 9 10 Console.WriteLine($"result=={result}"); 11 } 12 Console.WriteLine($"end Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); 13 Console.Read(); 14 }
The results are as follows:
You can see from the above that using t.Result or t.Wait() is equivalent to blocking the main thread, that is, waiting for the child thread to finish before the main thread can do the following, while await is not blocking the main thread
Four: Here's a code and decompilation look at how the bottom of async works


1 public class AwaitAsyncILSpy 2 { 3 public static void Show() 4 { 5 Console.WriteLine($"start1 {Thread.CurrentThread.ManagedThreadId.ToString("00")}"); 6 Async(); 7 Console.WriteLine($"aaa2 {Thread.CurrentThread.ManagedThreadId.ToString("00")}"); 8 } 9 private static async void Async() 10 { 11 Console.WriteLine($"ddd5 {Thread.CurrentThread.ManagedThreadId.ToString("00")}"); 12 await Task.Run(() => 13 { 14 Thread.Sleep(500); 15 Console.WriteLine($"bbb3 {Thread.CurrentThread.ManagedThreadId.ToString("00")}"); 16 }); 17 Console.WriteLine($"ccc4 {Thread.CurrentThread.ManagedThreadId.ToString("00")}"); 18 } 19 }
The results from the above analysis are: 15234
We use ILSPy to decompile the dll and get the following image:
By adding async to the above figure discovery method, the AsyncStateMachine state (which implements the IAsyncStateMachine interface) is added at decompilation time, and it works by:
Initialization state-1--Execution modifies state 0--Execution modifies state-1--Execution modifies state 0--If other states (-2) end, just like a traffic light, there is no limit to the cycle traffic light-green light-traffic light-green light
The underlying implementation is as follows: