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

来源:https://www.cnblogs.com/yilezhu/archive/2019/03/19/10555849.html
-Advertisement-
Play Games

眾所周知C 提供Async和Await關鍵字來實現非同步編程。在本文中,我們將共同探討並介紹什麼是Async 和 Await,以及如何在C 中使用Async 和 Await。 同樣本文的內容也大多是翻譯的,只不過加上了自己的理解進行了相關知識點的補充,如果你認為自己的英文水平還不錯,大可直接跳轉到文章 ...


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

作者:依樂祝
原文鏈接:https://www.cnblogs.com/yilezhu/p/10555849.html

寫在前面

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

想象一下當我們在處理UI和按鈕單擊時,我們需要運行一個長時間運行的方法,比如讀取一個大文件或其他需要很長時間的任務,在這種情況下,整個應用程式必須等待這個長時間運行的任務完成才算完成整個任務。

換句話說,如果同步應用程式中的任何進程被阻塞,則整個應用程式將被阻塞,我們的應用程式將停止響應,直到整個任務完成。

在這種情況下,非同步編程將非常有用。通過使用非同步編程,應用程式可以繼續進行不依賴於整個任務完成的其他工作。

在Async 和 await關鍵字的幫助下,使得非同步編程變得很簡單,而且我們將獲得傳統非同步編程的所有好處。

實例講解

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

我們可以使用簡單的多線程編程並行運行所有方法,但是它會阻塞UI並等待完成所有任務。要解決這個問題,我們必須在傳統編程中編寫很多的代碼,但是現在我們有了Async 和 await關鍵字,那麼我們將通過書寫很少的並且簡潔的代碼來解決這個問題。

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

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 1、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/


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • chapter08 數組的擴展 8.1 擴展運算符 8.1.1 擴展運算符的含義 如同rest運算符的逆運算,將一個數組轉換為用逗號分隔的參數序列。 8.1.2 代替數組的apply方法 apply方法可以將數組轉為函數的參數 8.1.3 擴展運算符的應用 合併數組 與解構賦值相結合 註意:如果擴展 ...
  • 編碼規範 1. 縮進 採用2個空格縮進,而不是tab縮進。空格在編輯器中與字元是等寬的,而tab可能因編輯器的設置不同。2個空格會讓代碼看起來緊湊、明快。 2. 變數聲明 永遠用var聲明變數,不加var時會將其變為全局變數,這樣可能會意外污染上下文,或是被意外污染。在ECMAScript5的scr ...
  • 前言 本案列僅針對剛剛入門vue學習的伙伴,博主也是剛剛在學基於vue cli搭建腳手架項目,對於前端大牛,可以移步。 快速搭建vue cli環境 如何搭建基於vue cli項目,這裡不再敘述,如果不會的伙伴可以自己百度。 項目搭建完成後,基本文件目錄如下: 打開我們剛剛創建的my project文 ...
  • 背景,做一個前面圖片寬度固定,後面寬度自適應,使用到了flex佈局,但是想讓後面div里文字不換行,超出以點點表示時,這時佈局就亂了,查了下,原來flex佈局與white-space:nowrap有影響 解決辦法,父div設置min-width:0即可 w3c上面是這樣說的 By default, ...
  • 三點註意事項 "JS作用域傳送門" JS沒有塊級作用域,只有全局作用域和局部作用域(函數作用域)。 JS中的作用域鏈,內部的作用域可以訪問到外部作用域中的變數和方法,而外部作用域不能訪問內部作用域的變數和方法。 當前作用域沒有此變數或方法,會向外部作用域尋找變數或方法。 閉包的兩種使用場景 函數作為 ...
  • clip-path介紹 clip-path 直譯過來就是裁剪路徑,使用SVG或形狀定義一個HTML元素的可見區域的方法。想象一下你在Photoshop中勾勒路徑的場景。MDN上是這樣介紹 clip-path的: clip-path屬性可以防止部分元素通過定義的剪切區域來顯示,僅通過顯示的特殊區域。剪 ...
  • 1 繪製文本 fillText(string,x,y,maxWidth) //填充試繪製文本 strokeText(string,x,y,maxWidth) 畫線試繪製文本 設置字體樣式: context.font 文字的字體樣式 可選屬性: font-style 字體樣式 font-variant ...
  • 一.概述 MVC的視圖與Razor頁面經常共用視覺和程式元素,通過使用佈局來完成,佈局還可減少重覆代碼。本章演示了以下內容的操作方法:(1)使用通用佈局,(2)自定義佈局,(3) 共用指令,(4)在呈現Razor頁面或MVC視圖之前運行通用代碼。 大多數 Web 應用都有一個通用佈局,可在頁面間切換 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...