ドキュメント
-
詳細情報: デリゲートを使用した非同期プログラミング
このブラウザーはサポートされなくなりました。
Microsoft Edge にアップグレードすると、最新の機能、セキュリティ更新プログラム、およびテクニカル サポートを利用できます。
.NET では、すべてのメソッドを非同期的に呼び出すことができます。 これを行うには、呼び出すメソッドと同じシグネチャを持つデリゲートを定義します。 このデリゲートには、共通言語ランタイムにより、適切なシグネチャが使用された BeginInvoke
および EndInvoke
メソッドが自動的に定義されます。
注意
非同期デリゲート (具体的には BeginInvoke
メソッドと EndInvoke
メソッド) は、.NET Compact Framework ではサポートされていません。
BeginInvoke
メソッドは、非同期呼び出しを開始します。 このメソッドは、非同期的に実行するメソッドと同じパラメーターと共に、2 つの省略可能な追加パラメーターを持っています。 最初のパラメーターは、同期呼び出しが完了したときに呼び出されるメソッドを参照する AsyncCallback デリゲートです。 2 番目のパラメーターは、コールバック メソッドに情報を渡すユーザー定義オブジェクトです。
BeginInvoke
からは制御がすぐに戻り、非同期呼び出しが完了するまで待機しません。
BeginInvoke
は IAsyncResultを返します。これを使用して非同期呼び出しの進捗状況を監視できます。
EndInvoke
メソッドは、非同期呼び出しの結果を取得します。 このメソッドは、 BeginInvoke
の後であればいつでも呼び出すことができます。 非同期呼び出しがまだ完了していない場合は、 EndInvoke
は非同期呼び出しが完了するまで呼び出し元スレッドをブロックします。
EndInvoke
のパラメーターには、非同期実行するメソッドの out
パラメーターと ref
パラメーター (Visual Basic では <Out>
ByRef
と ByRef
) と、IAsyncResult によって返された BeginInvoke
が含まれます。
注意
Visual Studio の IntelliSense 機能によって BeginInvoke
と EndInvoke
のパラメーターが表示されます。 Visual Studio または同様のツールを使用していない場合、または Visual Studio で C# を使用している場合は、これらのメソッドに定義されているパラメーターの説明については、 非同期プログラミング モデル (APM) を参照してください。
このトピックのコード例では、 BeginInvoke
と EndInvoke
を使用して非同期呼び出しを行う 4 つの一般的な方法を示します。
BeginInvoke
を呼び出した後、次の処理を行うことができます。
何か処理を実行した後、呼び出しが完了するまでブロックする EndInvoke
を呼び出します。
WaitHandle プロパティを使用して IAsyncResult.AsyncWaitHandle を取得し、その WaitOne メソッドを使用して WaitHandle が通知されるまで実行をブロックし、 EndInvoke
を呼び出します。
IAsyncResult によって返される BeginInvoke
をポーリングして非同期呼び出しが完了したかどうかを確認した後、 EndInvoke
を呼び出します。
コールバック メソッドのデリゲートを BeginInvoke
に渡します。 このメソッドは、非同期呼び出しが完了すると、 ThreadPool スレッドで実行されます。 コールバック メソッドは EndInvoke
を呼び出します。
重要
どの手法を使用する場合でも、常に EndInvoke
を呼び出して、非同期呼び出しを完了します。
次のコード例は、長時間実行される TestMethod
メソッドの非同期呼び出しを行うさまざまな方法を示します。
TestMethod
メソッドはコンソール メッセージを表示して処理が開始されたことを示し、しばらくスリープした後、終了します。
TestMethod
には out
パラメーターがあり、 BeginInvoke
および EndInvoke
のシグネチャへのそのようなパラメーターの追加方法を示します。
ref
パラメーターは同様に処理できます。
次のコード例は、 TestMethod
と、 AsyncMethodCaller
の非同期呼び出しに使用できる TestMethod
という名前のデリゲートの定義を示します。 コード例をコンパイルするには、 TestMethod
および AsyncMethodCaller
デリゲートの定義を含める必要があります。
using System;
using System.Threading;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncDemo
{
// The method to be executed asynchronously.
public string TestMethod(int callDuration, out int threadId)
{
Console.WriteLine("Test method begins.");
Thread.Sleep(callDuration);
threadId = Thread.CurrentThread.ManagedThreadId;
return String.Format("My call time was {0}.", callDuration.ToString());
}
}
// The delegate must have the same signature as the method
// it will call asynchronously.
public delegate string AsyncMethodCaller(int callDuration, out int threadId);
}
Imports System.Threading
Imports System.Runtime.InteropServices
Namespace Examples.AdvancedProgramming.AsynchronousOperations
Public Class AsyncDemo
' The method to be executed asynchronously.
Public Function TestMethod(ByVal callDuration As Integer, _
<Out> ByRef threadId As Integer) As String
Console.WriteLine("Test method begins.")
Thread.Sleep(callDuration)
threadId = Thread.CurrentThread.ManagedThreadId()
return String.Format("My call time was {0}.", callDuration.ToString())
End Function
End Class
' The delegate must have the same signature as the method
' it will call asynchronously.
Public Delegate Function AsyncMethodCaller(ByVal callDuration As Integer, _
<Out> ByRef threadId As Integer) As String
End Namespace
メソッドを非同期実行する最も簡単な方法は、デリゲートの BeginInvoke
メソッドを呼び出してメソッドの実行を開始し、メイン スレッドで何かの処理を実行した後、デリゲートの EndInvoke
メソッドを呼び出す方法です。
EndInvoke
は非同期呼び出しが完了するまで戻らないので、呼び出し元スレッドがブロックされる場合があります。 この手法はファイルやネットワーク操作を使用するときに適しています。
重要
EndInvoke
でブロックするため、ユーザー インターフェイスにサービスを提供するスレッドからは呼び出さないでください。
using System;
using System.Threading;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncMain3
{
public static void Main()
{
// The asynchronous method puts the thread id here.
int threadId;
// Create an instance of the test class.
AsyncDemo ad = new AsyncDemo();
// Create the delegate.
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
// Initiate the asynchronous call.
IAsyncResult result = caller.BeginInvoke(3000,
out threadId, null, null);
Thread.Sleep(0);
Console.WriteLine($"Main thread {Thread.CurrentThread.ManagedThreadId} does some work.");
// Call EndInvoke to wait for the asynchronous call to complete,
// and to retrieve the results.
string returnValue = caller.EndInvoke(out threadId, result);
Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
threadId, returnValue);
}
}
}
/* This example produces output similar to the following:
Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
*/
Imports System.Threading
Imports System.Runtime.InteropServices
Namespace Examples.AdvancedProgramming.AsynchronousOperations
Public Class AsyncMain
Shared Sub Main()
' The asynchronous method puts the thread id here.
Dim threadId As Integer
' Create an instance of the test class.
Dim ad As New AsyncDemo()
' Create the delegate.
Dim caller As New AsyncMethodCaller(AddressOf ad.TestMethod)
' Initiate the asynchronous call.
Dim result As IAsyncResult = caller.BeginInvoke(3000, _
threadId, Nothing, Nothing)
Thread.Sleep(0)
Console.WriteLine("Main thread {0} does some work.", _
Thread.CurrentThread.ManagedThreadId)
' Call EndInvoke to Wait for the asynchronous call to complete,
' and to retrieve the results.
Dim returnValue As String = caller.EndInvoke(threadId, result)
Console.WriteLine("The call executed on thread {0}, with return value ""{1}"".", _
threadId, returnValue)
End Sub
End Class
End Namespace
'This example produces output similar to the following:
'
'Main thread 1 does some work.
'Test method begins.
'The call executed on thread 3, with return value "My call time was 3000.".
WaitHandle を取得するには、 AsyncWaitHandle によって返される IAsyncResult の BeginInvoke
プロパティを使用します。
WaitHandle は非同期呼び出しが完了すると通知され、 WaitOne メソッドを呼び出すことによってこれを待機できます。
WaitHandleを使用する場合は、非同期呼び出しの完了前または完了後、 EndInvoke
を呼び出して結果を取得する前に、追加の処理を実行できます。
注意
EndInvoke
を呼び出す場合、待機ハンドルは自動的に閉じられません。 待機ハンドルへのすべての参照を解放すると、ガベージ コレクションが待機ハンドルをクリアするときにシステム リソースが解放されます。 待機ハンドルの使用が終了すると同時にシステム リソースを解放するには、 WaitHandle.Close メソッドを呼び出して破棄します。 破棄可能なオブジェクトが明示的に破棄されると、ガベージ コレクションはより効率的に動作します。
using System;
using System.Threading;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncMain2
{
static void Main()
{
// The asynchronous method puts the thread id here.
int threadId;
// Create an instance of the test class.
AsyncDemo ad = new AsyncDemo();
// Create the delegate.
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
// Initiate the asynchronous call.
IAsyncResult result = caller.BeginInvoke(3000,
out threadId, null, null);
Thread.Sleep(0);
Console.WriteLine($"Main thread {Thread.CurrentThread.ManagedThreadId} does some work.");
// Wait for the WaitHandle to become signaled.
result.AsyncWaitHandle.WaitOne();
// Perform additional processing here.
// Call EndInvoke to retrieve the results.
string returnValue = caller.EndInvoke(out threadId, result);
// Close the wait handle.
result.AsyncWaitHandle.Close();
Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
threadId, returnValue);
}
}
}
/* This example produces output similar to the following:
Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
*/
Imports System.Threading
Imports System.Runtime.InteropServices
Namespace Examples.AdvancedProgramming.AsynchronousOperations
Public Class AsyncMain
Shared Sub Main()
' The asynchronous method puts the thread id here.
Dim threadId As Integer
' Create an instance of the test class.
Dim ad As New AsyncDemo()
' Create the delegate.
Dim caller As New AsyncMethodCaller(AddressOf ad.TestMethod)
' Initiate the asynchronous call.
Dim result As IAsyncResult = caller.BeginInvoke(3000, _
threadId, Nothing, Nothing)
Thread.Sleep(0)
Console.WriteLine("Main thread {0} does some work.", _
Thread.CurrentThread.ManagedThreadId)
' Perform additional processing here and then
' wait for the WaitHandle to be signaled.
result.AsyncWaitHandle.WaitOne()
' Call EndInvoke to retrieve the results.
Dim returnValue As String = caller.EndInvoke(threadId, result)
' Close the wait handle.
result.AsyncWaitHandle.Close()
Console.WriteLine("The call executed on thread {0}, with return value ""{1}"".", _
threadId, returnValue)
End Sub
End Class
End Namespace
'This example produces output similar to the following:
'
'Main thread 1 does some work.
'Test method begins.
'The call executed on thread 3, with return value "My call time was 3000.".
IsCompleted によって返された IAsyncResult の BeginInvoke
プロパティを使用して、非同期呼び出しが完了したことを検出できます。 この方法は、ユーザー インターフェイスにサービスを提供するスレッドから非同期呼び出しを行う場合に使用します。 完了をポーリングすると、呼び出し元スレッドは、 ThreadPool スレッドで非同期呼び出しを実行しながら、実行を継続できます。
using System;
using System.Threading;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncMain
{
static void Main() {
// The asynchronous method puts the thread id here.
int threadId;
// Create an instance of the test class.
AsyncDemo ad = new AsyncDemo();
// Create the delegate.
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
// Initiate the asynchronous call.
IAsyncResult result = caller.BeginInvoke(3000,
out threadId, null, null);
// Poll while simulating work.
while(result.IsCompleted == false) {
Thread.Sleep(250);
Console.Write(".");
}
// Call EndInvoke to retrieve the results.
string returnValue = caller.EndInvoke(out threadId, result);
Console.WriteLine("\nThe call executed on thread {0}, with return value \"{1}\".",
threadId, returnValue);
}
}
}
/* This example produces output similar to the following:
Test method begins.
.............
The call executed on thread 3, with return value "My call time was 3000.".
*/
Imports System.Threading
Imports System.Runtime.InteropServices
Namespace Examples.AdvancedProgramming.AsynchronousOperations
Public Class AsyncMain
Shared Sub Main()
' The asynchronous method puts the thread id here.
Dim threadId As Integer
' Create an instance of the test class.
Dim ad As New AsyncDemo()
' Create the delegate.
Dim caller As New AsyncMethodCaller(AddressOf ad.TestMethod)
' Initiate the asynchronous call.
Dim result As IAsyncResult = caller.BeginInvoke(3000, _
threadId, Nothing, Nothing)
' Poll while simulating work.
While result.IsCompleted = False
Thread.Sleep(250)
Console.Write(".")
End While
' Call EndInvoke to retrieve the results.
Dim returnValue As String = caller.EndInvoke(threadId, result)
Console.WriteLine(vbCrLf & _
"The call executed on thread {0}, with return value ""{1}"".", _
threadId, returnValue)
End Sub
End Class
End Namespace
' This example produces output similar to the following:
'
'Test method begins.
'.............
'The call executed on thread 3, with return value "My call time was 3000.".
非同期呼び出しを開始したスレッドが結果を処理するスレッドである必要がない場合は、呼び出しが完了したときにコールバック メソッドを実行できます。 コールバック メソッドは ThreadPool スレッドで実行されます。
コールバック メソッドを使用するには、コールバック メソッドを表す BeginInvoke
デリゲートを AsyncCallback に渡す必要があります。 コールバック メソッドで使用される情報を含むオブジェクトを渡すこともできます。 コールバック メソッドでは、唯一のパラメーターである IAsyncResultを AsyncResult オブジェクトにキャストします。 こうすると、 AsyncResult.AsyncDelegate プロパティを使用して、呼び出しを開始するために使用したデリゲートを取得し、 EndInvoke
を呼び出すことができるようになります。
例に関する注意事項
threadId
の TestMethod
パラメーターは out
パラメーター (Visual Basic では [<Out>
ByRef
) であるため、その入力値が TestMethod
で使用されることはありません。
BeginInvoke
呼び出しにはダミー変数が渡されます。
threadId
パラメーターが ref
パラメーター (Visual Basic ではByRef
) であった場合、 BeginInvoke
と EndInvoke
の両方に渡すことができるように、変数はクラス レベルのフィールドであることが必要です。
BeginInvoke
に渡される状態情報は、コールバック メソッドが出力メッセージを書式指定するために使用する書式指定文字列です。 型 Objectとして渡されるため、状態情報を使用するには適切な型にキャストする必要があります。
コールバックは ThreadPool スレッドで作成されます。 ThreadPool スレッドは、メイン スレッドが終了した場合はアプリケーションの実行を継続しないバックグラウンド スレッドであるため、例で使用するメイン スレッドは、コールバックが終了できるまでスリープする必要があります。
using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncMain4
{
static void Main()
{
// Create an instance of the test class.
AsyncDemo ad = new AsyncDemo();
// Create the delegate.
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
// The threadId parameter of TestMethod is an out parameter, so
// its input value is never used by TestMethod. Therefore, a dummy
// variable can be passed to the BeginInvoke call. If the threadId
// parameter were a ref parameter, it would have to be a class-
// level field so that it could be passed to both BeginInvoke and
// EndInvoke.
int dummy = 0;
// Initiate the asynchronous call, passing three seconds (3000 ms)
// for the callDuration parameter of TestMethod; a dummy variable
// for the out parameter (threadId); the callback delegate; and
// state information that can be retrieved by the callback method.
// In this case, the state information is a string that can be used
// to format a console message.
IAsyncResult result = caller.BeginInvoke(3000,
out dummy,
new AsyncCallback(CallbackMethod),
"The call executed on thread {0}, with return value \"{1}\".");
Console.WriteLine($"The main thread {Thread.CurrentThread.ManagedThreadId} continues to execute...");
// The callback is made on a ThreadPool thread. ThreadPool threads
// are background threads, which do not keep the application running
// if the main thread ends. Comment out the next line to demonstrate
// this.
Thread.Sleep(4000);
Console.WriteLine("The main thread ends.");
}
// The callback method must have the same signature as the
// AsyncCallback delegate.
static void CallbackMethod(IAsyncResult ar)
{
// Retrieve the delegate.
AsyncResult result = (AsyncResult) ar;
AsyncMethodCaller caller = (AsyncMethodCaller) result.AsyncDelegate;
// Retrieve the format string that was passed as state
// information.
string formatString = (string) ar.AsyncState;
// Define a variable to receive the value of the out parameter.
// If the parameter were ref rather than out then it would have to
// be a class-level field so it could also be passed to BeginInvoke.
int threadId = 0;
// Call EndInvoke to retrieve the results.
string returnValue = caller.EndInvoke(out threadId, ar);
// Use the format string to format the output message.
Console.WriteLine(formatString, threadId, returnValue);
}
}
}
/* This example produces output similar to the following:
The main thread 1 continues to execute...
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
The main thread ends.
*/
Imports System.Threading
Imports System.Runtime.Remoting.Messaging
Namespace Examples.AdvancedProgramming.AsynchronousOperations
Public Class AsyncMain
Shared Sub Main()
' Create an instance of the test class.
Dim ad As New AsyncDemo()
' Create the delegate.
Dim caller As New AsyncMethodCaller(AddressOf ad.TestMethod)
' The threadId parameter of TestMethod is an <Out> parameter, so
' its input value is never used by TestMethod. Therefore, a dummy
' variable can be passed to the BeginInvoke call. If the threadId
' parameter were a ByRef parameter, it would have to be a class-
' level field so that it could be passed to both BeginInvoke and
' EndInvoke.
Dim dummy As Integer = 0
' Initiate the asynchronous call, passing three seconds (3000 ms)
' for the callDuration parameter of TestMethod; a dummy variable
' for the <Out> parameter (threadId); the callback delegate; and
' state information that can be retrieved by the callback method.
' In this case, the state information is a string that can be used
' to format a console message.
Dim result As IAsyncResult = caller.BeginInvoke(3000, _
dummy, _
AddressOf CallbackMethod, _
"The call executed on thread {0}, with return value ""{1}"".")
Console.WriteLine("The main thread {0} continues to execute...", _
Thread.CurrentThread.ManagedThreadId)
' The callback is made on a ThreadPool thread. ThreadPool threads
' are background threads, which do not keep the application running
' if the main thread ends. Comment out the next line to demonstrate
' this.
Thread.Sleep(4000)
Console.WriteLine("The main thread ends.")
End Sub
' The callback method must have the same signature as the
' AsyncCallback delegate.
Shared Sub CallbackMethod(ByVal ar As IAsyncResult)
' Retrieve the delegate.
Dim result As AsyncResult = CType(ar, AsyncResult)
Dim caller As AsyncMethodCaller = CType(result.AsyncDelegate, AsyncMethodCaller)
' Retrieve the format string that was passed as state
' information.
Dim formatString As String = CType(ar.AsyncState, String)
' Define a variable to receive the value of the <Out> parameter.
' If the parameter were ByRef rather than <Out> then it would have to
' be a class-level field so it could also be passed to BeginInvoke.
Dim threadId As Integer = 0
' Call EndInvoke to retrieve the results.
Dim returnValue As String = caller.EndInvoke(threadId, ar)
' Use the format string to format the output message.
Console.WriteLine(formatString, threadId, returnValue)
End Sub
End Class
End Namespace
' This example produces output similar to the following:
'
'The main thread 1 continues to execute...
'Test method begins.
'The call executed on thread 3, with return value "My call time was 3000.".
'The main thread ends.
.NET に関するフィードバック
.NET はオープンソース プロジェクトです。 フィードバックを提供するにはリンクを選択します。
ドキュメント
詳細情報: デリゲートを使用した非同期プログラミング
トレーニング
モジュール
Implement Asynchronous Tasks - Training
Learn how to implement asynchronous tasks in C# apps using the `async` and `await` keywords and how to run asynchronous tasks in parallel.
認定資格
マイクロソフト認定: Azure 開発者アソシエイト - Certifications
Azure Functions の作成、Web アプリの実装と管理、Azure ストレージを利用したソリューションの開発などを行うために、Microsoft Azure でエンド ツー エンドのソリューションを構築します。