C#高級編程9-第13章 異步編程

異步編程mysql

 


1)異步編程的重要性sql

  在C#5.0中提供了關鍵字:async和await數據庫

  使用異步編程後臺運行方法調用,程序的運行過程當中就不會一直處於等待中。便於用戶繼續操做.編程

  異步編程有3種模式:異步模式、基於事件的模式、基於任務的模式。併發

  基於任務的模式就使用了關鍵字。框架

2)異步模式異步

public delegate int AddHandler(int a,int b);
public class 加法類
{

public static int Add(int a, int b)
  {
     Console.WriteLine("開始計算:" + a + "+" + b);
     Thread.Sleep(1000);
     Console.WriteLine("計算完成!");
     return a + b;
   }

} 

  2.1)同步調用  async

    先調用,待處理異步編程

    

static void Main()
{
  Console.WriteLine("===== 同步調用 SyncInvokeTest =====");
  AddHandler handler = new AddHandler(加法類.Add);
  int result = handler.Invoke(1, 2);
  Console.WriteLine("繼續作別的事情。。。");
  Console.WriteLine(result);
  Console.ReadKey();
} 

 

  2.2)異步模式APM(Asynchronous Programming Model)學習

    先處理,待調用

    異步調用是一種相似消息或事件的機制,不過它的調用方向恰好相反,接口的服務在收到某種訊息或發生某種事件時,會主動通知客戶方(即調用客戶方的接口)。

    異步模式定義了開始調用方法和結束調用方法BeginInvoke和EndInvoke
    開始調用方法接受同步方法的全部輸入參數
    結束調用方法使用同步的全部輸出參數,按照同步方法返回類型返回結果。
    開始調用方法中包含了一個參數。該參數用於接受異步方法執行完成後調用的委託。
    開始調用方法返回異步結果接口IAsyncResult,用於驗證調用是否已經完成,而且一直等到方法的執行結束。

 

static void Main()
 {
   Console.WriteLine("===== 異步調用 AsyncInvokeTest =====");
    AddHandler handler = new AddHandler(加法類.Add);
    //IAsyncResult: 異步操做接口(interface)
    //BeginInvoke: 委託(delegate)的一個異步方法的開始
   IAsyncResult result = handler.BeginInvoke(1, 2, null, null);
   Console.WriteLine("繼續作別的事情。。。");
    //異步操做返回
   Console.WriteLine(handler.EndInvoke(result));
   Console.ReadKey();
}

異步模式實現了先進行全部事務的處理,最後等待處理的結果一塊兒反映給客戶端。

 

  2.3)基於事件的異步模式EAP(Event-based Asynchronous Pattern)

    基於事件的C#異步編程模式是比IAsyncResult模式更高級的一種異步編程模式   

    該異步模式具備如下優勢:

·                 「在後臺」執行耗時任務(例以下載和數據庫操做),但不會中斷您的應用程序。

·                 同時執行多個操做,每一個操做完成時都會接到通知(在通知中能夠區分是完成了哪一個操做)。

·                 等待資源變得可用,但不會中止(「掛起」)您的應用程序。

·                 使用熟悉的事件和委託模型與掛起的異步操做通訊。

    基於事件的異步模式須要如下三個類型的支持

      AsyncOperation:

      提供了對異步操做的生存期進行跟蹤的功能,包括操做進度通知和操做完成通知,並確保在正確的線程或上下文中調用客戶端的事件處理程序。

      AsyncOperationManager:

      爲AsyncOperation對象的建立提供了便捷方式,經過CreateOperation方法能夠建立多個AsyncOperation實例,實現對多個異步操做進行跟蹤

      WindowsFormsSynchronizationContext:

      該類繼承自SynchronizationContext類型,該類型是基於事件異步模式通訊的核心,該類型解決了「保證SendOrPostCallback委託在UI線程上執行」的問題

 

      

static void Main(string[] args)
        {
            object userState = "check";
            System.Collections.Specialized.HybridDictionary userStateToLifetime = new System.Collections.Specialized.HybridDictionary();
            AsyncOperation asyncOp = System.ComponentModel.AsyncOperationManager.CreateOperation(userState);

            lock (userStateToLifetime.SyncRoot)
            {
                if (userStateToLifetime.Contains(userState))
                {
                    throw new ArgumentException("同一時間不一樣IP操做過多,出現了併發", "操做狀態");
                }

                userStateToLifetime[userState] = asyncOp;
            }
            Action<object> eventHandler = (e) =>
            {
                userStateToLifetime[userState] = null;
                var arr = new List<int>();
                for (int i = 0; i < 10000000; i++)
                {
                    arr.Add(i);
                }
                Console.WriteLine("2.執行系統事件:"+ asyncOp.UserSuppliedState);
                asyncOp.PostOperationCompleted(new System.Threading.SendOrPostCallback(e as Action<object>), userState);
            };

            Action<object> onSelectedChange = (e) =>
            {
                
                Console.WriteLine("3.執行自定義事件開始" + asyncOp.UserSuppliedState);
                if (userStateToLifetime[userState] == null)
                {
                    Console.WriteLine("4.執行系統事件時被取消了");
                    return;
                }
                Console.WriteLine("5.執行自定義事件結束" + asyncOp.UserSuppliedState);
                asyncOp.OperationCompleted();
            };
            asyncOp.Post(new System.Threading.SendOrPostCallback(eventHandler), onSelectedChange);
            Console.WriteLine("1.作其餘的事情");
            Console.ReadKey();
        }

基於事件的異步模式與普通的異步模式不一樣點的是,基於事件的異步能夠在不一樣異步方法中串聯,能夠經過對象狀態通知跟蹤掛起的操做,取消掛起的操做,接收進度更新和增量結果。

所以咱們須要對多個異步方法進行互通消息時,使用事件的異步模式,通常的使用BeginInvoke和EndInvoke實現好了.

通常基於事件的異步方法以Async爲方法簽名後綴

 

  2.4)基於任務的異步模式TAP(Task-based Asynchronous Pattern)

 

咱們若是看到有類的方法名後綴以TaskAsync結尾,那就是基於任務的異步模式了。

基於任務的異步模式一樣也支持異步操做的取消和進度的報告的功能。

基於任務的異步模式使用Task類實現。還提供了關鍵字async和await

async異步執行

await等待任務返回

使用關鍵字async和await實現同步調用:

static void Main(string[] args)
        {
            Console.WriteLine("主線程測試開始..");
            AsyncMethod();
            Thread.Sleep(1000);
            Console.WriteLine("主線程測試結束..");
            Console.ReadLine();
        }

        static async void AsyncMethod()
        {
            Console.WriteLine("開始異步代碼");
            var result = await MyMethod();
            Console.WriteLine("異步代碼執行完畢");
        }

        static async Task<int> MyMethod()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("異步執行" + i.ToString() + "..");
                await Task.Delay(1000); //模擬耗時操做
            }
            return 0;
        }

從代碼中能夠看出.await和async關鍵字帶來的新優點.

對於運行結果來看,主線程正常操做,await將延遲操做持續響應.持續響應完畢後輸出異步代碼執行完畢。

咱們須要瞭解的一點是:
使用 await 的非同步方法必須由 async 關鍵字修改,await 關鍵字聲明的任務方法必須具備返回值,而且返回值是Task類型的,方法中若是使用了await關鍵字則,方法必須聲明爲異步的,必須用async進行聲明.

使用async能夠將方法、lamdba表達式、委託聲明爲異步的.

 

3)異步編程基礎

下面咱們將使用Task類來建立異步編程.

  3.1)建立任務

    基於任務的異步模式指定,在異步方法名後加上Async後綴,並返回一個任務,返回的是一個Task類型,看下面示例:

 

//  同步方法
static
string Greeting(string name) { Console.WriteLine("開始Greeting"); Thread.Sleep(3000); return string.Format("Hello, {0}", name); }
//  異步方法
static
Task<string> GreetingAsync(string name) { return Task.Run<string>(() => { Console.WriteLine("開始GreetingAsync"); return Greeting(name); }); }

 

  3.2)調用異步方法

使用await關鍵字調用返回任務的異步方法,使用await關鍵字須要有async修飾符聲明的方法
async修飾符只能用於返回Task或void方法,await只能用於返回task的方法

//  異步方法調用
private
async static void CallerWithAsync() { Console.WriteLine("started CallerWithAsync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId); string 結果 = await GreetingAsync("Stephanie"); Console.WriteLine(結果); Console.WriteLine("finished GreetingAsync in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId); }

 

  3.3)延續任務

Task類的ContinueWith方法定義了任務完成後調用的代碼,ContinueWith方法的委託參數接收已完成的任務做爲參數傳入,使用Result屬性訪問任務返回結果

//  延續任務ContinueWith
private
static void CallerWithContinuationTask() { Console.WriteLine("開始 CallerWithContinuationTask in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId); var t1 = GreetingAsync("Stephanie"); t1.ContinueWith(t => { string 結果 = t.Result; Console.WriteLine(結果); Console.WriteLine("finished CallerWithContinuationTask in thread {0} and task {1}", Thread.CurrentThread.ManagedThreadId, Task.CurrentId); }); }

  3.4)同步上下文

使用async和await關鍵字,當await完成以後,不須要處理,就能訪問ui線程,默認生成的代碼會把線程轉換到同步上下文的線程中

  3.5)使用多個異步方法

一個異步方法中能夠調用一個或多個異步方法.

1.使用await按順序調用異步方法

//  順序調用異步方法
private async static void MultipleAsyncMthods() { string s1 = await GreetingAsync("Stephanie"); string s2 = await GreetingAsync("Matthias"); Console.WriteLine("運行 全部方法.\n 結果 1: {0}\n 結果 2: {1}", s1, s2); }
//  
GreetingAsync異步方法第2次徹底獨立第一次調用的結果
 

2.使用組合器

若是異步方法不依賴於其餘方法,每一個異步方法都不使用await,而是把每一個異步方法的返回結果賦值給Task變量,運行會更快

一個組合器能夠接受多個同一類型的參數,並返回同一類型的值。多個同一類型的參數被組合成一個參數來傳遞。Task組合器接受多個Task對象做爲參數,返回一個Task

private async static void MultipleAsyncMethodsWithCombinators1()
{
     Task<string> t1 = GreetingAsync("Stephanie");
     Task<string> t2 = GreetingAsync("Matthias");
     await Task.WhenAll(t1, t2);
     Console.WriteLine("運行 全部方法.\n 結果 1: {0}\n 結果 2: {1}", t1.Result, t2.Result);
}

 

  3.6)轉換異步模式

使用Task類.Factory.FromAsync方法能夠將同步調用轉換爲異步調用

第一個參數爲開始調用BeginInvoke,第二個參數爲結束調用EndInvoke,第三個參數爲開始調用的委託參數值

private static async void ConvertingAsyncPattern()
 {
     string s = await Task<string>.Factory.FromAsync(BeginGreeting, EndGreeting, "Angela", null);
     Console.Write(s);
 
 }

 

4)錯誤處理

使用Task.Delay(1000)設置任務延遲時間

  4.1)異步方法的異常處理

異步方法的異常,使用await關鍵字進行等待,而且包含在try-catch代碼塊中

  4.2)多個異步方法的異常處理

多個異步方法的異常,使用組合器,處理異常

 

private async static void StartTwoTasksParallel()
        {
            Task t1 = null;
            try
            {
                t1 = ThrowAfter(2000, "first");
                Task t2 = ThrowAfter(1000, "second");
                await Task.WhenAll(t1, t2);
            }
            catch (Exception ex)
            {
                // just display the exception information of the first task that is awaited within WhenAll
                Console.WriteLine("handled {0}", ex.Message);
            }
        }

 

  4.3)使用AggregateException信息

經過定義的任務結果,遍歷結果的Exception.InnerExceptions獲取每個任務的異常信息

private static async void ShowAggregatedException()
        {
            Task taskResult = null;
            try
            {
                Task t1 = ThrowAfter(2000, "first");
                Task t2 = ThrowAfter(1000, "second");
                await (taskResult = Task.WhenAll(t1, t2));
            }
            catch (Exception ex)
            {
                // just display the exception information of the first task that is awaited within WhenAll
                Console.WriteLine("handled {0}", ex.Message);
                foreach (var ex1 in taskResult.Exception.InnerExceptions)
                {
                    Console.WriteLine("inner exception {0} from task {1}", ex1.Message, ex1.Source);
                }
            }
        }

 

5)取消

  5.1)開始取消任務

在System.Threading命名空間中定義了CancellationTokenSource類用於取消發送請求,使用Cancel方法進行取消或者使用CancelAfter設置指定時間後取消

  5.2)使用框架特性取消任務

經過CancellationTokenSource類對象cts.Token屬性能夠判斷任務是否取消,經過指定Token屬性進行取消任務

  5.3)取消自定義任務

經過CancellationTokenSource類對象cts.Token.ThrowIfCancellationRequested();

await Task.Run(()=>
{

  var images=req.Parse(resp);
  foreach(var image in images)
  {
    cts.Token.ThrowIfCancellatioRequested();
    searchInfo.List.Add(image);
  }
},cts.Token);

異步的三種模式:

1. 等待模式,在發起了異步方法以及作了一些其它處理以後,原始線程就中斷,而且等待異步方法完成以後再繼續。

2. 輪詢模式,原始線程按期檢查發起的線程是否完成,若是沒有則能夠繼續作一些其它的事情。

3. 回調模式,原始線程一直在執行,無需等待或檢查發起的線程是否完成。在發起的線程中的引用方法完成以後,發起的線程就會調用回調方法,由回調方法在調用EndInvoke以前處理異步方法的結構。

 

 

6)學習檢驗

  題目:

  1)  爲何要使用異步

  2)    異步解決了軟件應用中的哪些問題

  3)  Async和await分別是什麼

  4)  什麼是並行編程

  5)  委託包含的2種異步方法是什麼

  6)  基於事件的異步和APM異步調用的區別

  7)  同步與異步的區別

  8)  組合器是什麼

  9)  CancellationTokenSource類是用來作什麼的

  10)  Task類任務中使用什麼方法能夠延續任務調用

相關文章
相關標籤/搜索