C#5.0言語に追加された2つの新しいキーワードは async と await です。どちらも連携して、呼び出しスレッドをブロックせずにC#メソッドを非同期で実行します。
私の質問は、これらのメソッドは実際には複数のコアを利用して並列に実行されますか、それとも非同期メソッドは呼び出し元と同じスレッドコアで実行されますか?
C#5.0言語に追加された2つの新しいキーワードはasyncとawaitです。どちらも連携して、呼び出しスレッドをブロックせずにC#メソッドを非同期で実行します。
これは機能の目的を越えますが、非同期/待機機能に「クレジット」を与えすぎます。
await
は魔法のように同期メソッドを非同期的に実行させません。新しいスレッドを起動せず、新しいメソッドを実行しません。たとえば、スレッド。呼び出すメソッドは、それ自体を非同期で実行する方法を知っている必要があります。それを行うことを選択する方法は、そのビジネスです。
私の質問は、これらのメソッドは実際には複数のコアを利用して並列に実行されますか、それとも非同期メソッドは呼び出し元と同じスレッドコアで実行されますか?
繰り返しますが、これは完全に呼び出すメソッドまでです。 await
が行うことは、非同期タスクの継続として渡すことができるデリゲートにメソッドを書き換えるようにコンパイラーに指示することだけです。つまり、await FooAsync()
は「FooAsync()
を呼び出す」という意味であり、返されるものは、起動したばかりの非同期操作を表すものでなければなりません。非同期操作が完了したら、このデリゲートを呼び出す必要があります。」デリゲートには、呼び出されたときに現在のメソッドが「中断したところ」から再開するように見えるというプロパティがあります。
呼び出すメソッドが別のコアにアフィニティ化された別のスレッドで動作する場合は、すばらしいです。将来、UIスレッドでイベントハンドラーにpingを送信するタイマーを開始すると、すばらしいです。 await
は関係ありません。非同期ジョブが完了したら、中断したところから制御を再開できるようにするだけです。
あなたが尋ねなかったがおそらく持つべき質問は次のとおりです:
非同期タスクが完了し、コントロールが中断したところから再開するとき、実行は以前と同じスレッドで行われていますか?
状況によります。 UIスレッドからの何かを待つwinformsアプリケーションでは、UIスレッドでコントロールが再びピックアップします。コンソールアプリケーションでは、そうではないかもしれません。
エリック・リペルトは素晴らしい答えを持っています。 async
並列処理についてもう少し詳しく説明したかっただけです。
単純な「シリアル」アプローチでは、一度に1つだけawait
を実行します。
static void Process()
{
Thread.Sleep(100); // Do CPU work.
}
static async Task Test()
{
await Task.Run(Process);
await Task.Run(Process);
}
この例では、Test
メソッドはProcess
をスレッドプールにキューイングし、完了すると、Process
をスレッドプールに再度キューイングします。 Test
メソッドは、〜200ms後に完了します。いつでも、1つのスレッドだけが実際に進行を進めています。
これを並列化する簡単な方法は、Task.WhenAll
:
static void Process()
{
Thread.Sleep(100); // Do CPU work.
}
static async Task Test()
{
// Start two background operations.
Task task1 = Task.Run(Process);
Task task2 = Task.Run(Process);
// Wait for them both to complete.
await Task.WhenAll(task1, task2);
}
この例では、Test
メソッドはProcess
をスレッドプールに2回キューイングし、両方が完了するまで待機します。 Test
メソッドは約100ms後に完了します。
Task.WhenAll
(およびTask.WhenAny
)は、単純な並列処理をサポートするためにasync
/await
とともに導入されました。ただし、より高度なものが必要な場合でも、TPLはそのまま存在します(真のCPUにバインドされた並列処理がTPLに適しています)。 TPLはasync
/await
でうまく機能します。
基本的なasync
並列処理について into to async
blog post と、Ericが言及した「コンテキスト」で取り上げます。
非同期メソッドは待機可能なオブジェクト(GetAwaiter
メソッドを持つオブジェクト)を返し、await
キーワードを使用してメソッドを呼び出すと、コンパイラーはそのオブジェクトを使用するコードを生成できます。また、awaitキーワードなしでこのようなメソッドを呼び出しせず、オブジェクトを明示的に使用することもできます。
オブジェクトは非同期アクションをカプセル化します。これは、別のスレッドで実行される場合とされない場合があります。 Eric Lippertの記事 C#5.0の非同期:パート4:魔法ではない は、1つのスレッドのみを含む非同期プログラミングの例を検討します。
async
とawait
はTPLに基づいているため、非常に似た動作をするはずです。デフォルトでは、別のスレッドで実行されているかのように扱う必要があります。