多線程編程學習筆記——async和await(一)

来源:http://www.cnblogs.com/chillsrc/archive/2017/12/18/8057913.html
-Advertisement-
Play Games

通過前面的文章,已經學習了怎麼使用線程,怎麼使用線程同步,怎麼使用線程池,怎麼使用任務並行庫。儘管通過上面的學習,對於線程的使用越來越簡單。有沒有更簡單的方法呢。 C# 5.0之後,微軟在c#語言中添加了兩個關鍵字async與await,這是在TPL上面的更高一級的抽象,真正簡化了異... ...


接上文 多線程編程學習筆記——任務並行庫(一)

接上文 多線程編程學習筆記——任務並行庫(二)

 接上文 多線程編程學習筆記——任務並行庫(三)

  接上文 多線程編程學習筆記——任務並行庫(四)

 

        通過前面的文章,已經學習了怎麼使用線程,怎麼使用線程同步,怎麼使用線程池,怎麼使用任務並行庫。儘管通過上面的學習,對於線程的使用越來越簡單。有沒有更簡單的方法呢。

       C# 5.0之後,微軟在c#語言中添加了兩個關鍵字async與await,這是在TPL上面的更高一級的抽象,真正簡化了非同步編程的編程方式,從而有助於我們編寫出真正健壯少bug的非同步應用程式。下麵我先來看一個最簡單的示例。

async Task<string> AsyncHello()
{

await Task.Delay(TimeSpan.FromSeconds(2));
Return “ Hello world”;
}

         使用async標記非同步函數,建議返回async Task<T>。

         Await只能使用在有async標誌的方法內部。在async標記的方法內部最少要有一個await,當然,如果一個也沒有,編譯也不會報錯,但是會有編譯警告。如下圖。

     

       上面的代碼在執行完await調用的代碼之行後該方法會直接返回。如果同步執行,執行線程會阻塞2秒之後返回結果,本示例里在執行完await操作後,立即將工作線程放回線程池中,我們會非同步等待。2秒後,我們會從線程池中取得工作線程並繼續運行其中剩餘的非同步方法。這就允許我們在等待的2秒的時間里可以重用線程池中的線程,這對提高應用程式的可伸縮性非常重要。通過使用async與await我們擁有了線性的程式控制流程,但是執行過程卻是非同步的。

 

一、   使用await獲取非同步操作結果

        本示例是學習await如何獲取非同步操作結果。同時會與TPL進行比較。

 1.示例代碼如下。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading; 

namespace ThreadAsyncDemo
{

    class Program
    {
        static void Main(string[] args)
        {

            Task t = AsyncWithTPL();
            t.Wait();
            t = AsyncWithAwait();
            t.Wait();
            Console.Read();
        }

 

        static Task AsyncWithTPL()
        {
            Task<string> task1 = GetInfoAsync("Task 1");

            Task task2 = task1.ContinueWith(task =>
              Console.WriteLine(task1.Result), TaskContinuationOptions.NotOnFaulted);
            Task task3 = task1.ContinueWith(task =>
              Console.WriteLine(task1.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted);
            return Task.WhenAny(task2, task1);

        }

        async static Task AsyncWithAwait()
        {
            try
            {
                string result = await GetInfoAsync("Task 4");
                Console.WriteLine(result);
            }

            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);

            }
        } 

        async static Task<string> GetInfoAsync(string name)
        {

            await Task.Delay(TimeSpan.FromSeconds(2));
            //throw  new Exception("拋出異常信息!"); 

            return string.Format(" Task {0} 正在運行線上程 ID={1}上。這個工作線程是否是線程池中的線程:{2}", name, 
Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread); } } }

 

 2.程式運行的結果如下圖。

 

         程式同時運行了兩個非同步操作。其中一個是標準的TPL代碼,另一個使用了async與await兩個關鍵字。AsyncWithTPL啟動了一個任務,運行兩秒之後返回關於工作線程信息的字元串。然後我們定義了一個後續操作,用於在非同步操作完成後列印出操作結果,還有另一個後續操作,用於萬一有錯誤時,列印出異常信息。最終返回了一個代表其中一個後續操作任務的任務,並等等其在主函數中完成。

        在asyncWithAwait方法中,我們對任務使用await並得到了相同 的結果。這和編寫普通的同步代碼的風格一樣,即我們獲取了任務的結果,列印了出來,如果任務完成時帶有錯誤則捕獲異常。關鍵不同的是這實際上是一個非同步操作。使用await後,c#立即創建了一個任務,其中一個有後續操作任務,包含了await操作符後面的所有剩餘代碼。這個新任務也處理了異常。然後這個任務返回 到主方法並等待共完成 。

       因此可以看出程式中的兩段代碼在概念上是相同的,使用await由編譯 器隱式地處理了非同步代碼。

  3. 我們把上面註釋的拋出異常的代碼,取消註釋,然後運行程式。得到如下圖的結果。

 

            註:在gui與asp.net之類的環境 中不推薦 使用task.wait和taskResult方法同,因為如果代碼寫的不好,很容易導致死鎖。

 

二、   在Lambda表達式中使用await操作符

         本示例學習如何在lambda表達式中使用await。將學習如何編寫一個使用了await的匿名方法,並且獲取非同步執行該方法的結果。

 1.示例代碼如下。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading; 

namespace ThreadAsyncDemo
{

    class Program
    {

        static void Main(string[] args)
        {

            Task t = AsyncProcess();
            t.Wait();       
            Console.Read();
        } 

        async static Task AsyncProcess()
        {

            Func<String, Task<string>> asyncLambda = async name =>
            {

                await Task.Delay(TimeSpan.FromSeconds(2));
                return string.Format(" Task {0} 正在運行線上程 ID={1}上。這個工作線程是線程池的線程:{2}" ,name, 
Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread); };
string result = await asyncLambda("async lambda"); Console.WriteLine(result); } } }

 

2.程式運行結果,如下圖。

 

        首先不能在main方法中使用async,我們將非同步函數移到了asyncProcess中,然後使用async關鍵字聲明瞭一個lambda表達式。由於 任何lambda表達式的類型都不能通過lambda自身來推斷,所以不得不顯示地指定類型為一字元串,並返回一個Task<string>對象 。

        然後,我們定義 了lambda表達式體,這個方法雖然定義返回的是一個Task<string>對象 ,但實際上返回的是字元串,卻沒有編譯錯誤。這是因為c#編譯器自動 產生了一個任務並返回給我們。

       最後一步就是列印出lambda 表達式執行後的結果。

 


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

-Advertisement-
Play Games
更多相關文章
  • load是一個方法,在程式文件中,只有ruby遇到它的時候才會執行。Ruby不會搜索整個文件去執行load命令。也就是說,當Ruby解釋器遇到它的時候,它才會去尋找它要載入的文件。這意味著需要載入的文件名可以在運行時動態地決定。甚至可以在條件語句中包含一個load指令的調用,讓它只有在條件尾true ...
  • 分別使用過List中Distinct(),GroupBy()實現鏈表的去重。 1.先上效果: 一維鏈表中分別有元素“aa”,"bb",'aa','aa',"cc",使用Distinct()方法後輸出 aa,bb,cc 二維鏈表中類型為ClassA類型,其中對象的屬性A分別為1,1,2,3,1,使用G ...
  • .NET Core 兩種GC模式: Server GC / Workstation GC Server GC : 主要應用於多處理器系統,並且作為ASP.NET Core宿主的預設配置。它會為每個處理器都創建一個GC Heap,並且會並行執行回收操作。該模式的GC可以最大化吞吐量和較好的收縮性。這種... ...
  • 一.什麼是值類型?什麼引用類型? 1.值類型的值是存儲在棧上的。引用類型是存在堆上的。 2.值類型變數聲明之後,不管是否已經分配記憶體,編譯器在堆上為其分配記憶體。 3.引用類型聲明的時候,這時候只在棧中分配一小片記憶體用於容納一個地址,此時候並沒有為其分配堆上的記憶體地址,當new一個實例的時候,真正創建 ...
  • PS:寫這個主要是基礎差,寫這麼一個主要是為了自己查漏補缺,不會的搞會了。會了搞的更會。順便整理知識。 目錄 1.C#知識點之:值類型和引用類型 ...
  • 先來看看下麵一個類中的一些方法: class Bc { public double Add(double number1, double number2) { return number1 + number2; } public double Multiply(double number1, dou ...
  • 最近做的項目,上線後一切正常,過段時間管理員反饋用戶導出EXCEL報錯,前臺獲取用戶列表不顯示,查找問題找到是微信昵稱、emoji表情導致報錯, emoji表情介紹 由於微信介面中對於emoji表情使用的是UTF-8的二進位字元串,並沒有解碼,表現就是當收到微信端用戶發來的emoji表情時,顯示為一 ...
  • 類只能繼承一個類,不能繼承多個類,但可以繼承多個介面Interface。 類是對象的抽象,抽象類是類的抽象,而介面是行為的抽象。 下麵Insus.NET創建2個介面: 介面是統一行為,抽象是從現在有代碼中,把上同代碼抽取出來的一個抽象方法,而介面卻是相反。不清楚有什麼子類存在,行為具體實現也不確定。 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...