非同期プログラミングモデルとイベントベースの非同期パターンの実際の違いは何ですか?
どのアプローチをいつ使用するか?
非同期プログラミングモデル(APM)は、BeginMethod(...)
とEndMethod(...)
ペアで表示されるモデルです。
たとえば、 APM実装Socket
を使用すると次のようになります。
var socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// ...
socket.BeginReceive(recvBuffer, 0, recvBuffer.Length,
SocketFlags.None, ReceiveCallback, null);
void ReceiveCallback(IAsyncResult result)
{
var bytesReceived = socket.EndReceive(result);
if (bytesReceived > 0) { // Handle received data here. }
if (socket.Connected)
{
// Keep receiving more data...
socket.BeginReceive(recvBuffer, 0, recvBuffer.Length,
SocketFlags.None, ReceiveCallback, null);
}
}
イベントベースの非同期パターン(EAPMethodAsync(...)
)は、とCancelAsync(...)
ペアで表示されるモデルです。通常、Completed
イベントがあります。BackgroundWorker
このパターンの良い例です。
C#4.5以降、両方ともタスク並列処理ライブラリ(TPLasync/await
)を使用するパターンに置き換えられました。メソッド名の後にマークが付けられ、通常は待機可能またはを返します。.NET 4.5をターゲットにできる場合は、APMまたはEAPの設計でこのパターンを使用する必要があります。Async
Task
Task<TResult>
たとえば、(潜在的に大きな)ファイルを非同期的に圧縮します。
public static async Task CompressFileAsync(string inputFile, string outputFile)
{
using (var inputStream = File.Open(inputFile, FileMode.Open, FileAccess.Read))
using (var outputStream = File.Create(outputFile))
using (var deflateStream = new DeflateStream(outputStream, CompressionMode.Compress))
{
await inputStream.CopyToAsync(deflateStream);
deflateStream.Close();
outputStream.Close();
inputStream.Close();
}
}
クライアント コードの POV から:
EAP: 名前が "Completed" で終わるイベントのイベント ハンドラーを設定し、名前が "Async" で終わるメソッドを呼び出します。名前に「Cancel」を含むメソッドを呼び出すと、キャンセルされる場合があります。
APM: 名前が「Begin」で始まるメソッドを呼び出し、その結果をポーリングするか、コールバックを受信してから、「End」で始まるメソッドを呼び出します。
私が知る限り、APM はほとんどの BCL IO クラスと WCF に実装されており、主に低レベルのキャンセル不可能な操作です (キャンセルする場合は結果を無視するだけです)。EAP は、より高いレベルのクラス、つまりファイルをダウンロードするクラスで見られます。このクラスでは、複数のステップとある種の意味のあるキャンセル動作があります。
したがって、どちらを実装するかを選択する必要がある場合 (そして、意図的にこれら 2 つに制限している場合)、実行していることがキャンセル可能かどうかにかかっていると思います。
クライアント コードの POV から、常に選択肢が得られるとは限りません。可能であれば、C# 4.5 タスクを使用するのがおそらく最善です。それらは、ラッパーを介して古い非同期メカニズムのいずれかと連携できます。
包括的な回答は、MSDN の記事「イベント ベースの非同期パターンをいつ実装するかを決定する」に記載されています。
この記事の主なアイデア (および質問への短い回答) は、「IAsyncResult パターンを生成するオプションを使用して、デフォルトでイベント ベースのパターンを生成する」のように聞こえます。