共用方式為


非同步設計模式概觀

非同步模式所提供的創新之一是,呼叫端可決定特定呼叫是否應該為同步的。為受呼叫的物件做額外的程式設計以支援其用戶端的非同步行為,是沒有必要的;非同步委派在模式中有提供這點。Common Language Runtime 會處理呼叫端和受呼叫物件觀點間的差異。受呼叫物件可能選擇明確支援非同步行為,不是因為它可以比一般架構更有效率來實作,就是因為它只想支援其呼叫端的非同步行為。然而,建議您要讓這類受呼叫物件遵照非同步的設計模式來公開非同步作業。

型別安全 (Type Safety) 是非同步模式的另一個創新。特別是對非同步委派來說,以 .NET Framework 和 Common Language Runtime 為目標的語言編譯器 (Compiler) 可以為對應至一般 Invoke 方法的開始和結束作業 (例如,BeginInvokeEndInvoke) 的方法簽名碼進行型別安全處理。這是值得注意的,因為編譯器會替非同步委派將同步呼叫 (Synchronous Call) 劃分成開始和結束作業,並使它只能夠傳遞有效參數。

這模式背後的基本想法如下:

  1. 呼叫端決定特定呼叫是否應該為同步的。
  2. 進行額外的程式設計來支援其用戶端非同步行為的受呼叫物件,但這是沒有必要的。Common Language Runtime 基礎結構應該能夠處理呼叫端和受呼叫物件觀點之間的差異。
  3. 受呼叫物件可能選擇明確支援非同步行為,不是因為它可以比一般架構更有效率來實作,就是因為它只想支援其呼叫端的非同步行為。然而,建議您要讓這類受呼叫物件遵照非同步的設計模式來公開非同步作業。
  4. 編譯器為非同步委派產生 BeginInvokeEndInvoke 的型別安全方法簽名碼。
  5. .NET Framework 提供支援非同步程式設計模型所需要的服務。這類服務的範例部分清單為:
    • 同步處理的基本項目,例如監視器和讀取器寫入器鎖定。
    • 執行緒和執行緒集區。
    • 同步建構,例如支援在物件上等候的容器。
    • 對基本基礎結構項目的公開,例如 IMessage 物件和執行緒集區。

模式將同步呼叫劃分為組成部份:開始作業、結束作業和結果物件。請考慮下列範例,其中 Factorize 方法很有可能要耗用大量時間來完成。

public class PrimeFactorizer
{
   public bool Factorize(int factorizableNum, ref int primefactor1, ref int primefactor2)
   {
      // Determine whether factorizableNum is prime.
      // If it is prime, return true. Otherwise, return false.
      // If it is prime, place factors in primefactor1 and primefactor2.
   }
}

如果遵照非同步模式,類別庫 (Class Library) 寫入器會加入 BeginFactorizeEndFactorize 方法,將同步作業 (Synchronous Operation) 劃分成兩個非同步作業:

public class PrimeFactorizer
{
   public bool Factorize(
int factorizableNum, 
ref int primefactor1, 
ref int primefactor2)
   {
      // Determine whether factorizableNum is prime.
      // if it is prime, return true; otherwise return false.
      // if it is prime, place factors in primefactor1 and primefactor2
   }

   public IAsyncResult BeginFactorize(
int factorizableNum, 
ref int primefactor1, 
ref int primefactor2, 
AsyncCallback callback, 
Object state)
   {
     // Begin factoring asynchronously, and return a result object,
   }

   public bool EndFactorize(
ref int primefactor1, 
ref int primefactor2,
IAsyncResult asyncResult
)
   {
     // End (or complete) the factorizing, 
     // return the results, 
     // and obtain the prime factors.
   }
}

伺服器將非同步作業分割成兩個邏輯部份:從用戶端接受輸入並啟動非同步作業的部份,和提供非同步作業的結果給用戶端的部份。

除了非同步作業所需的輸入之外,第一部份也接受非同步作業完成時要呼叫的 AsyncCallback 委派。第一個部分傳回可等待物件,其實作用戶端所用的 IAsyncResult 介面,來決定非同步作業的狀態。

伺服器也利用它傳回給用戶端的可等候的物件來保持任何與非同步作業相關的狀態。用戶端透過提供可等候的物件,使用第二部份來取得非同步作業的結果。

用戶端可用來啟始非同步作業的選項:

  1. 在開始非同步呼叫時提供回呼委派。

    public class Driver1
    {
      public PrimeFactorizer primeFactorizer;
    
      public void Results(IAsyncResult asyncResult)
      {
        int primefactor1=0; 
        int primefactor2=0;
    
        bool prime = primeFactorizer.EndFactorize(
    ref primefactor1, 
    ref primefactor2,
    asyncResult);
      }
    
      public void Work()
      {
        int factorizableNum=1000589023, 
        int primefactor1=0; 
        int primefactor2=0;
        Object state = new Object();
    
        primeFactorizer = new PrimeFactorizer();
        AsyncCallback callback = new Callback(this.Results);
        IAsyncResult asyncResult = primeFactorizer.BeginFactorize(
    factorizableNum, 
    ref primefactor1, 
    ref primefactor2, 
    callback, 
    state);
      }
    }
    
  2. 在開始非同步呼叫時不提供回呼委派。

    public class Driver2
    {
      public static void Work()
      {
        int factorizableNum=1000589023, 
        int primefactor1=0; 
        int primefactor2=0;
        Object state = new Object();
    
        PrimeFactorizer primeFactorizer = new PrimeFactorizer();
        AsyncCallback callback = new Callback(this.Results);
        IAsyncResult asyncResult = primeFactorizer.BeginFactorize(
    factorizableNum, 
    ref primefactor1, 
    ref primefactor2, 
    callback, 
    state);
    
        bool prime = primeFactorizer.EndFactorize(
    ref primefactor1, 
    ref primefactor2,
    asyncResult);
      }
    }
    

請參閱

非同步方法簽名碼 | IAsyncResult 介面 | 非同步作業的 AsyncCallback 委派 | 非同步程式設計