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

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

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

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

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

 

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

       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>。async

         Await只能使用在有async標誌的方法內部。在async標記的方法內部最少要有一個await,固然,若是一個也沒有,編譯也不會報錯,可是會有編譯警告。以下圖。異步編程

     

       上面的代碼在執行完await調用的代碼之行後該方法會直接返回。若是同步執行,執行線程會阻塞2秒以後返回結果,本示例裏在執行完await操做後,當即將工做線程放回線程池中,咱們會異步等待。2秒後,咱們會從線程池中取得工做線程並繼續運行其中剩餘的異步方法。這就容許咱們在等待的2秒的時間裏能夠重用線程池中的線程,這對提升應用程序的可伸縮性很是重要。經過使用async與await咱們擁有了線性的程序控制流程,可是執行過程倒是異步的。函數

 

1、   使用await獲取異步操做結果post

        本示例是學習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方法同,由於若是代碼寫的很差,很容易致使死鎖。

 

2、   在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 表達式執行後的結果。

相關文章
相關標籤/搜索