多線程編程學習筆記——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
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...