イベントベースの非同期パターンの概要Event-based Asynchronous Pattern Overview

多数のタスクを同時に実行しながら、ユーザーの操作にも応答するアプリケーションには、通常、複数のスレッドを使用するデザインが必要です。Applications that perform many tasks simultaneously, yet remain responsive to user interaction, often require a design that uses multiple threads. System.Threading 名前空間は、高性能なマルチスレッド アプリケーションを作成するのに必要なすべてのツールを提供します。ただし、これらのツールを効果的に使用するには、マルチスレッド ソフトウェア エンジニアリングの豊富な経験が必要です。The System.Threading namespace provides all the tools necessary to create high-performance multithreaded applications, but using these tools effectively requires significant experience with multithreaded software engineering. 比較的単純なマルチスレッド アプリケーションの場合は、BackgroundWorker コンポーネントが簡単なソリューションを提供します。For relatively simple multithreaded applications, the BackgroundWorker component provides a straightforward solution. より高度な非同期アプリケーションの場合は、イベント ベースの非同期パターンに準拠したクラスの実装を検討してください。For more sophisticated asynchronous applications, consider implementing a class that adheres to the Event-based Asynchronous Pattern.

イベント ベースの非同期パターンを使用すると、マルチスレッド デザイン固有の多くの複雑な問題を気にせずに、マルチスレッド アプリケーションの利点を活用できます。The Event-based Asynchronous Pattern makes available the advantages of multithreaded applications while hiding many of the complex issues inherent in multithreaded design. このパターンをサポートするクラスを使用すると、次のことが可能になります。Using a class that supports this pattern can allow you to:

  • ダウンロードやデータベース操作などの時間がかかるタスクを、アプリケーションを中断せずに、"バックグラウンド" で行うことができます。Perform time-consuming tasks, such as downloads and database operations, "in the background," without interrupting your application.

  • 複数の操作を同時に実行し、それぞれの操作が完了するたびに通知を受け取ることができます。Execute multiple operations simultaneously, receiving notifications when each completes.

  • アプリケーションを停止 ("ハングアップ") せずに、リソースが使用可能な状態になるまで待機できます。Wait for resources to become available without stopping ("hanging") your application.

  • 使い慣れたイベントおよびデリゲートのモデルを使用して、保留中の非同期操作と通信できます。Communicate with pending asynchronous operations using the familiar events-and-delegates model. イベント ハンドラーおよびデリゲートの使い方の詳細については、イベントに関するページを参照してください。For more information on using event handlers and delegates, see Events.

イベント ベースの非同期パターンをサポートするクラスには、MethodNameAsync という名前のメソッドが 1 つ以上含まれます。これらのメソッドは、同期バージョンに対応するもので、現在のスレッドで同じ操作を行います。クラスには、MethodNameCompleted イベントや MethodNameAsyncCancel (または単に CancelAsync) メソッドが含まれる場合もあります。A class that supports the Event-based Asynchronous Pattern will have one or more methods named MethodNameAsync. These methods may mirror synchronous versions, which perform the same operation on the current thread. The class may also have a MethodNameCompleted event and it may have a MethodNameAsyncCancel (or simply CancelAsync) method.

PictureBox は、イベント ベースの非同期パターンをサポートする一般的なコンポーネントです。PictureBox is a typical component that supports the Event-based Asynchronous Pattern. イメージを同期的にダウンロードするには、その Loadメソッドを呼び出します。ただし、イメージのサイズが大きい場合や、ネットワークの接続速度が遅い場合は、ダウンロード操作が完了して Load の呼び出しから戻るまで、アプリケーションが停止 ("ハングアップ") します。You can download an image synchronously by calling its Load method, but if the image is large, or if the network connection is slow, your application will stop ("hang") until the download operation is completed and the call to Load returns.

イメージの読み込み中にもアプリケーションを実行し続けるには、LoadAsync メソッドを呼び出して、他のイベントを処理する場合と同様に、LoadCompleted イベントを処理します。If you want your application to keep running while the image is loading, you can call the LoadAsync method and handle the LoadCompleted event, just as you would handle any other event. LoadAsync メソッドを呼び出すと、ダウンロードを別のスレッドで ("バックグラウンド" で) 続行しながら、アプリケーションを実行し続けることができます。When you call the LoadAsync method, your application will continue to run while the download proceeds on a separate thread ("in the background"). イメージの読み込み操作が完了すると、イベント ハンドラーが呼び出されます。イベント ハンドラーは、AsyncCompletedEventArgs パラメーターを調べて、ダウンロードが正常に完了したかどうかを確認できます。Your event handler will be called when the image-loading operation is complete, and your event handler can examine the AsyncCompletedEventArgs parameter to determine if the download completed successfully.

イベント ベースの非同期パターンでは、非同期操作をキャンセルできる必要があります。PictureBox コントロールでは、その CancelAsync メソッドでこの要件をサポートしています。The Event-based Asynchronous Pattern requires that an asynchronous operation can be canceled, and the PictureBox control supports this requirement with its CancelAsync method. CancelAsync を呼び出すと、保留中のダウンロードを停止する要求が送信されます。タスクがキャンセルされると、LoadCompleted イベントが発生します。Calling CancelAsync submits a request to stop the pending download, and when the task is canceled, the LoadCompleted event is raised.

注意事項

CancelAsync 要求が作成されると同時に、ダウンロードが終了する可能性もあります。このような場合、Cancelled にはキャンセルの要求が反映されません。It is possible that the download will finish just as the CancelAsync request is made, so Cancelled may not reflect the request to cancel. これは競合状態と呼ばれる、マルチスレッド プログラミングの一般的な問題です。This is called a race condition and is a common issue in multithreaded programming. マルチスレッド プログラミングの問題の詳細については、「Managed Threading Best Practices」 (管理されたスレッドのベスト プラクティス) を参照してください。For more information on issues in multithreaded programming, see Managed Threading Best Practices.

イベント ベースの非同期パターンの特性Characteristics of the Event-based Asynchronous Pattern

イベント ベースの非同期パターンには、特定のクラスでサポートされている操作の複雑さに応じて、複数の形式があります。The Event-based Asynchronous Pattern may take several forms, depending on the complexity of the operations supported by a particular class. 最もシンプルなクラスには、単一の MethodNameAsync メソッドと、このメソッドに対応する MethodNameCompleted イベントが含まれる場合があります。The simplest classes may have a single MethodNameAsync method and a corresponding MethodNameCompleted event. より複雑なクラスには、複数の MethodNameAsync メソッドと、それぞれに対応する MethodNameCompleted イベント、およびこれらのメソッドの同期バージョンが含まれる場合があります。More complex classes may have several MethodNameAsync methods, each with a corresponding MethodNameCompleted event, as well as synchronous versions of these methods. クラスでは、各非同期メソッドの、キャンセル、進行状況のレポート、およびインクリメンタル結果をオプションでサポートできます。Classes can optionally support cancellation, progress reporting, and incremental results for each asynchronous method.

また、非同期メソッドでは複数の保留中の呼び出し (複数の同時呼び出し) をサポートして、他の保留中の操作が完了するまで、コードを何度も呼び出せるようにできます。An asynchronous method may also support multiple pending calls (multiple concurrent invocations), allowing your code to call it any number of times before it completes other pending operations. このような状況を適切に処理するには、アプリケーションで各操作の完了を追跡する必要があります。Correctly handling this situation may require your application to track the completion of each operation.

イベント ベースの非同期パターンの例Examples of the Event-based Asynchronous Pattern

SoundPlayer および PictureBox コンポーネントは、イベント ベースの非同期パターンのシンプルな実装です。The SoundPlayer and PictureBox components represent simple implementations of the Event-based Asynchronous Pattern. WebClient および BackgroundWorker コンポーネントは、イベント ベースの非同期パターンのより複雑な実装です。The WebClient and BackgroundWorker components represent more complex implementations of the Event-based Asynchronous Pattern.

パターンに準拠したクラス宣言の例を次に示します。Below is an example class declaration that conforms to the pattern:

Public Class AsyncExample  
    ' Synchronous methods.  
    Public Function Method1(ByVal param As String) As Integer   
    Public Sub Method2(ByVal param As Double)   

    ' Asynchronous methods.  
    Overloads Public Sub Method1Async(ByVal param As String)   
    Overloads Public Sub Method1Async(ByVal param As String, ByVal userState As Object)   
    Public Event Method1Completed As Method1CompletedEventHandler  

    Overloads Public Sub Method2Async(ByVal param As Double)   
    Overloads Public Sub Method2Async(ByVal param As Double, ByVal userState As Object)   
    Public Event Method2Completed As Method2CompletedEventHandler  

    Public Sub CancelAsync(ByVal userState As Object)   

    Public ReadOnly Property IsBusy () As Boolean  

    ' Class implementation not shown.  
End Class  
public class AsyncExample  
{  
    // Synchronous methods.  
    public int Method1(string param);  
    public void Method2(double param);  

    // Asynchronous methods.  
    public void Method1Async(string param);  
    public void Method1Async(string param, object userState);  
    public event Method1CompletedEventHandler Method1Completed;  

    public void Method2Async(double param);  
    public void Method2Async(double param, object userState);  
    public event Method2CompletedEventHandler Method2Completed;  

    public void CancelAsync(object userState);  

    public bool IsBusy { get; }  

    // Class implementation not shown.  
}  

架空の AsyncExample クラスには 2 つのメソッドがあり、いずれも同期および非同期の呼び出しをサポートしています。The fictitious AsyncExample class has two methods, both of which support synchronous and asynchronous invocations. 同期のオーバーロードは、呼び出し元スレッドで操作を呼び出しおよび実行する任意のメソッドと同様に動作します。操作に時間がかかる場合は、呼び出しから戻るまでにかなりの遅延が発生する場合があります。The synchronous overloads behave like any method call and execute the operation on the calling thread; if the operation is time-consuming, there may be a noticeable delay before the call returns. 非同期のオーバーロードは、別のスレッドで操作を開始して即座に戻ります。これにより、操作を "バックグラウンド" で実行しながら、呼び出し元スレッドを続行できます。The asynchronous overloads will start the operation on another thread and then return immediately, allowing the calling thread to continue while the operation executes "in the background."

非同期メソッドのオーバーロードAsynchronous Method Overloads

非同期操作には、基本的に単一呼び出しと複数呼び出しの 2 つのオーバーロードがあります。There are potentially two overloads for the asynchronous operations: single-invocation and multiple-invocation. これら 2 つの形式はそのメソッド シグネチャで区別できます。複数呼び出しの形式には、userState という名前の追加のパラメーターがあります。You can distinguish these two forms by their method signatures: the multiple-invocation form has an extra parameter called userState. この形式を使用すると、保留中の非同期操作が完了するのを待たずに、コードで Method1Async(string param, object userState) を複数回呼び出すことができます。This form makes it possible for your code to call Method1Async(string param, object userState) multiple times without waiting for any pending asynchronous operations to finish. 一方、直前の呼び出しが完了する前に Method1Async(string param) を呼び出そうとすると、メソッドにより InvalidOperationException が発生します。If, on the other hand, you try to call Method1Async(string param) before a previous invocation has completed, the method raises an InvalidOperationException.

複数呼び出しのオーバーロードの userState パラメーターにより、非同期操作を区別できます。The userState parameter for the multiple-invocation overloads allows you to distinguish among asynchronous operations. Method1Async(string param, object userState) の各呼び出しに一意な値 (GUID やハッシュ コードなど) を指定すると、各操作が完了したときに、イベント ハンドラーは、どの操作のインスタンスが完了イベントを発生させたのかを確認できます。You provide a unique value (for example, a GUID or hash code) for each call to Method1Async(string param, object userState), and when each operation is completed, your event handler can determine which instance of the operation raised the completion event.

保留中の操作の追跡Tracking Pending Operations

複数呼び出しのオーバーロードを使用する場合は、保留中のタスクの userState オブジェクト (タスク ID) を追跡する必要があります。If you use the multiple-invocation overloads, your code will need to keep track of the userState objects (task IDs) for pending tasks. Method1Async(string param, object userState) の呼び出しごとに、通常は新しい一意な userState オブジェクトを生成し、それをコレクションに追加します。For each call to Method1Async(string param, object userState), you will typically generate a new, unique userState object and add it to a collection. この userState オブジェクトに対応するタスクが完了イベントを発生させると、完了メソッドの実装は AsyncCompletedEventArgs.UserState を調べて、それをコレクションから削除します。When the task corresponding to this userState object raises the completion event, your completion method implementation will examine AsyncCompletedEventArgs.UserState and remove it from your collection. このように使用すると、userState パラメーターはタスク ID の役割を果たします。Used this way, the userState parameter takes the role of a task ID.

注意

複数呼び出しのオーバーロードの呼び出しでは、userState に一意な値を指定するように注意が必要です。You must be careful to provide a unique value for userState in your calls to multiple-invocation overloads. タスク ID が一意でないと、非同期クラスが ArgumentException をスローします。Non-unique task IDs will cause the asynchronous class throw an ArgumentException.

保留中の操作のキャンセルCanceling Pending Operations

非同期操作を完了前にいつでもキャンセルできることは重要です。It is important to be able to cancel asynchronous operations at any time before their completion. イベント ベースの非同期パターンを実装するクラスには、CancelAsync メソッド (非同期メソッドが 1 つだけの場合) または MethodNameAsyncCancel メソッド (複数の非同期メソッドがある場合) が含まれます。Classes that implement the Event-based Asynchronous Pattern will have a CancelAsync method (if there is only one asynchronous method) or a MethodNameAsyncCancel method (if there are multiple asynchronous methods).

複数呼び出しを可能にするメソッドは userState パラメーターを受け取ります。これは、各タスクの有効期間を追跡するのに使用できます。Methods that allow multiple invocations take a userState parameter, which can be used to track the lifetime of each task. CancelAsyncuserState パラメーターを受け取ります。このパラメーターにより、特定の保留中のタスクを取り消すことができます。CancelAsync takes a userState parameter, which allows you to cancel particular pending tasks.

保留中の操作を一度に 1 つだけサポートする Method1Async(string param) のようなメソッドは、キャンセルできません。Methods that support only a single pending operation at a time, like Method1Async(string param), are not cancelable.

進行状況の更新およびインクリメンタル結果の受信Receiving Progress Updates and Incremental Results

イベント ベースの非同期パターンに準拠するクラスは、進行状況およびインクリメンタル結果を追跡するイベントをオプションで提供します。A class that adheres to the Event-based Asynchronous Pattern may optionally provide an event for tracking progress and incremental results. 通常、これは ProgressChanged または MethodNameProgressChanged という名前で、その対応するイベント ハンドラーは ProgressChangedEventArgs パラメーターを受け取ります。This will typically be named ProgressChanged or MethodNameProgressChanged, and its corresponding event handler will take a ProgressChangedEventArgs parameter.

ProgressChanged イベントのイベント ハンドラーは、ProgressChangedEventArgs.ProgressPercentage プロパティを調べて、非同期タスクの何パーセントが完了したのかを確認できます。The event handler for the ProgressChanged event can examine the ProgressChangedEventArgs.ProgressPercentage property to determine what percentage of an asynchronous task has been completed. このプロパティは 0 ~ 100 の範囲です。これを使用すると、Valuear の ProgressBar プロパティを更新できます。This property will range from 0 to 100, and it can be used to update the Value property of a ProgressBar. 複数の非同期操作が保留中の場合は、ProgressChangedEventArgs.UserState プロパティを使用して、どの操作が進行状況をレポートしているのかを判別できます。If multiple asynchronous operations are pending, you can use the ProgressChangedEventArgs.UserState property to distinguish which operation is reporting progress.

一部のクラスは、非同期操作の進行に応じて、インクリメンタル結果をレポートします。Some classes may report incremental results as asynchronous operations proceed. これらの結果は ProgressChangedEventArgs から派生したクラス内に保存され、派生クラスのプロパティとして表示されます。These results will be stored in a class that derives from ProgressChangedEventArgs and they will appear as properties in the derived class. ProgressChanged イベントのイベント ハンドラーのこれらの結果へは、ProgressPercentage プロパティにアクセスするのと同じようにアクセスできます。You can access these results in the event handler for the ProgressChanged event, just as you would access the ProgressPercentage property. 複数の非同期操作が保留中の場合は、UserState プロパティを使用して、どの操作がインクリメンタル結果をレポートしているのかを判別できます。If multiple asynchronous operations are pending, you can use the UserState property to distinguish which operation is reporting incremental results.

参照See Also

ProgressChangedEventArgs
BackgroundWorker
AsyncCompletedEventArgs
方法: イベントベースの非同期パターンをサポートするコンポーネントを使用するHow to: Use Components That Support the Event-based Asynchronous Pattern
方法: バックグラウンドで操作を実行するHow to: Run an Operation in the Background
方法: バックグラウンド操作を使用するフォームを実装するHow to: Implement a Form That Uses a Background Operation
イベント ベースの非同期パターンを使用したマルチスレッド プログラミングMultithreaded Programming with the Event-based Asynchronous Pattern
イベントベースの非同期パターンを実装するための推奨される手順Best Practices for Implementing the Event-based Asynchronous Pattern
イベントベースの非同期パターンをいつ実装するかの決定Deciding When to Implement the Event-based Asynchronous Pattern