C# 中的Async 和 Await 的用法詳解

衆所周知C#提供Async和Await關鍵字來實現異步編程。在本文中,咱們將共同探討並介紹什麼是Async 和 Await,以及如何在C#中使用Async 和 Await。
一樣本文的內容也大可能是翻譯的,只不過加上了本身的理解進行了相關知識點的補充,若是你認爲本身的英文水平還不錯,大可直接跳轉到文章末尾查看原文連接進行閱讀。html

做者:依樂祝
原文連接:http://www.javashuo.com/article/p-wkkdrrxi-ck.html編程

寫在前面

自從C# 5.0時代引入async和await關鍵字後,異步編程就變得流行起來。尤爲在如今的.NET Core時代,若是你的代碼中沒有出現async或者await關鍵字,都會讓人感受到很奇怪。c#

想象一下當咱們在處理UI和按鈕單擊時,咱們須要運行一個長時間運行的方法,好比讀取一個大文件或其餘須要很長時間的任務,在這種狀況下,整個應用程序必須等待這個長時間運行的任務完成纔算完成整個任務。多線程

換句話說,若是同步應用程序中的任何進程被阻塞,則整個應用程序將被阻塞,咱們的應用程序將中止響應,直到整個任務完成。異步

在這種狀況下,異步編程將很是有用。經過使用異步編程,應用程序能夠繼續進行不依賴於整個任務完成的其餘工做。async

在Async 和 await關鍵字的幫助下,使得異步編程變得很簡單,並且咱們將得到傳統異步編程的全部好處。異步編程

實例講解

假設咱們分別使用了兩種方法,即Method 1和Method 2,這兩種方法不相互依賴,而Method 1須要很長時間才能完成它的任務。在同步編程中,它將執行第一個Method 1,並等待該方法的完成,而後執行Method 2。所以,這將是一個時間密集型的過程,即便這兩種方法並不相互依賴。線程

咱們可使用簡單的多線程編程並行運行全部方法,可是它會阻塞UI並等待完成全部任務。要解決這個問題,咱們必須在傳統編程中編寫不少的代碼,可是如今咱們有了Async 和 await關鍵字,那麼咱們將經過書寫不多的而且簡潔的代碼來解決這個問題。翻譯

此外,咱們還將看到更多的示例,若是任何第三個方法(如Method 3)都依賴於Method 1,那麼它將在Wait關鍵字的幫助下等待Method 1的完成。code

Async 和 await是代碼標記,它標記代碼位置爲任務完成後控件應該恢復的位置。

下面讓咱們舉幾個例子來更好進行理解吧

C#中Async 和 await關鍵字的示例

咱們將採用控制檯應用程序進行演示。

第一個例子

在這個例子中,咱們將採起兩個不相互依賴的方法。

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");  
            }  
        });  
    }  
  
  
    public static void Method2()
    {  
        for (int i = 0; i < 25; i++)
        {  
Console.WriteLine(" Method 2");  
        }  
    }  
}

在上面給出的代碼中,Method 1和Method 2不相互依賴,咱們是從主方法調用的。

在這裏,咱們能夠清楚地看到,方法1和方法2並非在等待對方完成。

輸出

img

如今來看第二個例子,假設咱們有Method 3,它依賴於Method 1

第二個例子

在本例中,Method 1將總長度做爲整數值返回,咱們在Method 3中以長度的形式傳遞一個參數,它來自Method 1。

在這裏,在傳遞Method 3中的參數以前,咱們必須使用AWAIT關鍵字,爲此,咱們必須使用調用方法中的async 關鍵字。

在控制檯應用程序的Main方法中,由於不能使用async關鍵字而不能使用await 關鍵字,由於它會給出下面給出的錯誤。(可是若是你使用的是C#7.1及以上的方法是不會有問題的,由於C#7.1及以上的語法支持Mian方法前加async)

img
咱們將建立一個新的方法,做爲CallMethod,在這個方法中,咱們將調用咱們的全部方法,分別爲Method 一、Method 2和Method 3。

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);
    }  
}

在上面給出的代碼中,Method 3須要一個參數,即Method 1的返回類型。在這裏,await關鍵字對於等待Method 1任務的完成起着相當重要的做用。

輸出

img

第三個例子

.NET Framework4.5中有一些支持API,Windows運行時包含支持異步編程的方法。

在Async 和 await關鍵字的幫助下,咱們能夠在實時項目中使用全部這些,以便更快地執行任務。

包含異步方法的API有HttpClient, SyndicationClient, StorageFile, StreamWriter, StreamReader, XmlReader, MediaCapture, BitmapEncoder, BitmapDecoder 等。

在本例中,咱們將異步讀取大型文本文件中的全部字符,並獲取全部字符的總長度。

class Program
{  
    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;
    }  
}

在上面給出的代碼中,咱們調用ReadFile方法來讀取文本文件的內容,並獲取文本文件中總字符的長度。

在sampleText.txt中,文件包含了太多的字符,所以讀取全部字符須要很長時間。

在這裏,咱們使用異步編程從文件中讀取全部內容,因此它不會等待從這個方法得到一個返回值並執行其餘代碼行,可是它必須等待下面給出的代碼行,由於咱們使用的是等待關鍵字,咱們將對下面給出的代碼行使用返回值。

int length = await task;
Console.WriteLine(" Total length: " + length);

隨後,將按順序執行其餘代碼行。

Console.WriteLine(" After work 1");  
Console.WriteLine(" After work 2");

輸出

img

最後

在這裏,咱們必須瞭解很是重要的一點,若是咱們沒有使用await 關鍵字,那麼該方法就做爲一個同步方法。編譯器將向咱們顯示警告,但不會顯示任何錯誤。
像上面這種簡單的方式同樣,咱們能夠在C#代碼中使用async 和await關鍵字來愉快的進行異步編程了。
最後的最後感謝你們的閱讀!
本文大部份內容翻譯自:https://www.c-sharpcorner.com/article/async-and-await-in-c-sharp/

相關文章
相關標籤/搜索