C#中Async与Await的用法总结--博客搬运
In this article, you'll learn what C# async and C# await keywords are and how to use async and await in C# code.
Nowadays, Asynchronous programming is very popular with the help of the async and await keywords in C#. When we are dealing with UI, and on button click, we use a long-running method like reading a large file or something else which will take a long time, in that case, the entire application must wait to complete the whole task. In other words, if any process is blocked in a synchronous application, the whole application gets blocked, and our application stops responding until the whole task completes.
Asynchronous programming is very helpful in this condition. By using Asynchronous programming, the Application can continue with the other work that does not depend on the completion of the entire task.
We will get all the benefits of traditional Asynchronous programming with much less effort with the help of async and await keywords.
Suppose we are using two methods as Method1 and Method2 respectively, and both the methods are not dependent on each other, and Method1 takes a long time to complete its task. In Synchronous programming, it will execute the first Method1 and it will wait for the completion of this method, and then it will execute Method2. Thus, it will be a time-intensive process even though both methods are not depending on each other.
We can run all the methods parallelly by using simple thread programming, but it will block UI and wait to complete all the tasks. To come out of this problem, we have to write too many codes in traditional programming, but if we use the async and await keywords, we will get the solutions in much less code.
Also, we are going to see more examples, and if any third Method, as Method3 has a dependency of method1, then it will wait for the completion of Method1 with the help of await keyword.
Async and await in C# are the code markers, which marks code positions from where the control should resume after a task completes.
Let’s start with practical examples for understanding the programming concept.
Code examples of C# async await
We are going to take a console application for our demonstration.
Example 1
In this example, we are going to take two methods, which are not dependent on each other.
Code sample
class Program { static void Main(string[] args) { Method1(); Method2(); Console.ReadKey(); } public static async Task Method1() { await Task.Run(() => { for (int i = 0; i < 100; i++) { Console.WriteLine(" Method 1"); // Do something Task.Delay(100).Wait(); } }); } public static void Method2() { for (int i = 0; i < 25; i++) { Console.WriteLine(" Method 2"); // Do something Task.Delay(100).Wait(); } } }
In the code given above, Method1 and Method2 are not dependent on each other and we are calling from the Main method.
Here, we can clearly see Method1, and Method2 are not waiting for each other.
Output
Now, coming to the second example, suppose we have Method3, which is dependent on Method1
Example 2
In this example, Method1 is returning the total length as an integer value and we are passing a parameter as a length in a Method3, which is coming from Method1.
Here, we have to use await keyword before passing a parameter in Method3 and for it, we have to use the async keyword from the calling method.
If we are using C# 7 or less, then we cannot use async keyword in the Main method for the console Application because it will give the error below.
We are going to create a new method as callMethod and in this method, we are going to call our all Methods as Method1, Method2, and Method3, respectively.
Code sample C# 7
class Program { static void Main(string[] args) { callMethod(); Console.ReadKey(); } public static async void callMethod() { Task<int> task = Method1(); Method2(); int count = await task; Method3(count); } public static async Task<int> Method1() { int count = 0; await Task.Run(() => { for (int i = 0; i < 100; i++) { Console.WriteLine(" Method 1"); count += 1; } }); return count; } public static void Method2() { for (int i = 0; i < 25; i++) { Console.WriteLine(" Method 2"); } } public static void Method3(int count) { Console.WriteLine("Total count is " + count); } }
Code sample C# 9
class Program { static async Task Main(string[] args) { await callMethod(); Console.ReadKey(); } public static async Task callMethod() { Method2(); var count = await Method1(); Method3(count); } public static async Task<int> Method1() { int count = 0; await Task.Run(() => { for (int i = 0; i < 100; i++) { Console.WriteLine(" Method 1"); count += 1; } }); return count; } public static void Method2() { for (int i = 0; i < 25; i++) { Console.WriteLine(" Method 2"); } } public static void Method3(int count) { Console.WriteLine("Total count is " + count); } }
In the code given above, Method3 requires one parameter, which is the return type of Method1. Here, await keyword is playing a vital role for waiting of Method1 task completion.
Output
Real-time example
There are some supporting API's from the .NET Framework 4.5 and the Windows runtime contains methods that support async programming.
We can use all of these in the real-time project with the help of async and await keyword for the faster execution of the task.
Some APIs that contain async methods are HttpClient, SyndicationClient, StorageFile, StreamWriter, StreamReader, XmlReader, MediaCapture, BitmapEncoder, BitmapDecoder etc.
In this example, we are going to read all the characters from a large text file asynchronously and get the total length of all the characters.
Sample code
class Program { ke static void Main() { Task task = new Task(CallMethod); task.Start(); task.Wait(); Console.ReadLine(); } static async void CallMethod() { string filePath = "E:\\sampleFile.txt"; Task<int> task = ReadFile(filePath); Console.WriteLine(" Other Work 1"); Console.WriteLine(" Other Work 2"); Console.WriteLine(" Other Work 3"); int length = await task; Console.WriteLine(" Total length: " + length); Console.WriteLine(" After work 1"); Console.WriteLine(" After work 2"); } static async Task<int> ReadFile(string file) { int length = 0; Console.WriteLine(" File reading is stating"); using (StreamReader reader = new StreamReader(file)) { // Reads all characters from the current position to the end of the stream asynchronously // and returns them as one string. string s = await reader.ReadToEndAsync(); length = s.Length; } Console.WriteLine(" File reading is completed"); return length; } }
In the code given above, we are calling a ReadFile method to read the contents of a text file and get the length of the total characters present in the text file.
In our sampleText.txt, the file contains too many characters, so It will take a long time to read all the characters.
Here, we are using async programming to read all the contents from the file, so it will not wait to get a return value from this method and execute the other lines of code. Still it has to wait for the line of code given below because we are using await keywords, and we are going to use the return value for the line of code given below.
int length = await task; Console.WriteLine(" Total length: " + length);
Subsequently, other lines of code will be executed sequentially.
Console.WriteLine(" After work 1"); Console.WriteLine(" After work 2");
Output
Here, we have to understand very important points that if we are not using await keyword, then the method works as a synchronous method. The compiler will show the warning to us, but it will not show any error.
We can use async and await keywords in C# to implement async programming in this easy way.
using System; using System.IO; using System.Threading.Tasks; namespace Async_和_Await_的用法详解3 { class Program { /// <summary> /// .NET Framework4.5中有一些支持API,Windows运行时包含支持异步编程的方法。 ///在Async 和 await关键字的帮助下,我们可以在实时项目中使用所有这些,以便更快地执行任务。 ///包含异步方法的API有HttpClient, SyndicationClient, StorageFile, StreamWriter, StreamReader, XmlReader, MediaCapture, BitmapEncoder, BitmapDecoder 等。 ///在本例中,我们将异步读取大型文本文件中的所有字符,并获取所有字符的总长度。 /// </summary> /// <param name="args"></param> static void Main() { Action act = new Action(CallMethod); Task task = new Task(act);//代表一个异步操作 // Initializes a new System.Threading.Tasks.Task with the specified action. // 参数: // action: // The delegate that represents the code to execute in the task. task.Start(); task.Wait(); Console.ReadLine(); } static async void CallMethod() { string filePath = "sampleFile.txt"; //string content = ""; Task<int> task = ReadFile(filePath); Console.WriteLine("////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////"); Task<string> taskStr = ReadFileStr(filePath); Console.WriteLine("////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////"); Console.WriteLine(" Other Work 1"); Console.WriteLine(" Other Work 2"); Console.WriteLine(" Other Work 3"); Console.WriteLine("////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////"); int length = await task; string str = await taskStr; Console.WriteLine(" Total length: " + length); Console.WriteLine("////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////"); Console.WriteLine(str); Console.WriteLine("////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////"); Console.WriteLine(" After work 1"); Console.WriteLine(" After work 2"); Console.WriteLine(" After work 3"); } static async Task<int> ReadFile(string filePath) //异步方法不能使用ref out 或 in 等关键字参数 { int length = 0; Console.WriteLine(" FileWordCount reading is stating"); using (StreamReader reader = new StreamReader(filePath)) { // Reads all characters from the current position to the end of the stream asynchronously // and returns them as one string. string stringContent = await reader.ReadToEndAsync(); length = stringContent.Length; } Console.WriteLine(" FileWordCount reading is completed"); return length; } static async Task<string> ReadFileStr(string filePath) //异步方法不能使用ref out 或 in 等关键字参数 { /// int length = 0; string stringContent=""; Console.WriteLine(" ReadFileStr reading is stating"); using (StreamReader reader = new StreamReader(filePath)) { // Reads all characters from the current position to the end of the stream asynchronously // and returns them as one string. // 返回结果: // A task that represents the asynchronous read operation. The value of the TResult // parameter contains a string with the characters from the current position to // the end of the stream. stringContent = await reader.ReadToEndAsync(); //length = stringContent.Length; } Console.WriteLine(" ReadFileStr reading is completed"); return stringContent; } } } /* 在上面给出的代码中,我们调用ReadFile方法来读取文本文件的内容,并获取文本文件中总字符的长度。 在sampleText.txt中,文件包含了太多的字符,因此读取所有字符需要很长时间。 在这里,我们使用异步编程从文件中读取所有内容,所以它不会等待从这个方法获得一个返回值并执行其他代码行, 但是它必须等待下面给出的代码行,因为我们使用的是等待关键字,我们将对下面给出的代码行使用返回值。 在这里,我们必须了解非常重要的一点,如果我们没有使用await 关键字,那么该方法就作为一个同步方法。编译器将向我们显示警告,但不会显示任何错误。 像上面这种简单的方式一样,我们可以在C#代码中使用async 和await关键字来愉快的进行异步编程了。 */