非同期デザイン パターンの概要
非同期パターンによって提供される新機能の 1 つに、特定の呼び出しを非同期にする必要があるかどうかを、呼び出し元が決定できるという点があります。呼び出されたオブジェクトが、クライアントによる非同期動作をサポートするためのプログラミングを行う必要はありません。この処理はパターンに含まれており、非同期デリゲートによって実行されます。呼び出し元と呼び出されたオブジェクトのビューの違いは、共通言語ランタイムによって処理されます。呼び出されたオブジェクトでは、非同期動作を明示的にサポートできます。これにより、汎用アーキテクチャよりも効率的に非同期動作を実装したり、その呼び出し元による非同期動作だけをサポートしたりできます。ただし、このようなオブジェクトでは、非同期デザイン パターンに従って非同期動作を公開することをお勧めします。
タイプ セーフも非同期パターンの新機能の 1 つです。特に非同期デリゲートでは、.NET Framework を対象にした言語コンパイラと共通言語ランタイムにより、通常の Invoke メソッドに割り当てられる開始操作と終了操作 (たとえば BeginInvoke と EndInvoke) のメソッド シグネチャをタイプ セーフにできます。これには大きな意味があり、コンパイラは、同期呼び出しを非同期呼び出しデリゲートの開始操作と終了操作に分割し、有効なパラメータだけが渡されるようにします。
非同期デザイン パターンの基本的な処理手順は次のとおりです。
- 呼び出し元で、特定の呼び出しを非同期にする必要があるかどうか判断します。
- 呼び出されたオブジェクトで、クライアントによる非同期動作をサポートするための追加のプログラミングを行います。ただし、この処理は省略できます。呼び出し元と呼び出されたオブジェクトのビューの違いは、共通言語ランタイムのインフラストラクチャによって処理されます。
- 呼び出されたオブジェクトでは、非同期動作を明示的にサポートできます。これにより、汎用アーキテクチャよりも効率的に非同期動作を実装したり、その呼び出し元による非同期動作だけをサポートしたりできます。ただし、このようなオブジェクトでは、非同期デザイン パターンに従って非同期動作を公開することをお勧めします。
- コンパイラは、非同期デリゲートの BeginInvoke および EndInvoke に対するタイプ セーフなメソッド シグネチャを生成します。
- .NET Framework には、非同期プログラミング モデルをサポートするために必要なサービスが用意されています。このようなサービスの例を次に示します。
- 同期プリミティブ。モニタ、リーダー ライタ ロックなど。
- スレッドとスレッド プール。
- 同期構成体。オブジェクトの待機をサポートするコンテナなど。
- 基になるインフラストラクチャへの公開。IMessage オブジェクト、スレッド プールなど。
パターンによって、同期呼び出しは、開始操作、終了操作、結果オブジェクトという連続する 3 つの部分に分割されます。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.
}
}
非同期パターンを使用する場合は、クラス ライブラリ ライタによって BeginFactorize メソッドと EndFactorize メソッドが追加され、同期操作が 2 つの非同期操作に分割されます。
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.
}
}
サーバーは、非同期操作を 2 つの論理的部分に分割します。1 つはクライアントからの入力を取得し、非同期操作を呼び出す部分です。もう 1 つは、非同期操作の結果をクライアントに提供する部分です。
最初の部分では、非同期操作に必要な入力のほかに、非同期操作が完了したときに呼び出される AsyncCallback デリゲートも取得されます。最初の部分では、IAsyncResult インターフェイスを実装する待機可能オブジェクトが返されます。クライアントは、このインターフェイスを使用して非同期操作の状態を判断します。
サーバーも、クライアントに返す待機可能オブジェクトを使用して、非同期操作に関連付けられたあらゆる状態を管理します。クライアントは、2 番目の部分を使用し、待機可能オブジェクトを提供することによって、非同期操作の結果を取得します。
クライアントが非同期操作を開始するときに使用できるオプションを次に示します。
非同期呼び出しの開始時にコールバック デリゲートを提供する。
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); } }
非同期操作の開始時にコールバック デリゲートを提供しない。
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 デリゲート | 非同期呼び出しの組み込み