C#でasync/awaitキーワードのコツと、非同期プログラミングを容易にする方法を理解しています。db呼び出しなどのI/Oバインドタスクが実行されている間、スレッドを他の場所で使用できます。
Async/awaitがI/Oバウンドタスク用であり、CPUバウンドタスク用ではないことを何度も読みました。 CPUバウンドタスクは、別のバックグラウンドスレッドで実行する必要があります。これらの中で数回言及 ビデオ 。大丈夫。
ただし、Task.Run
を使用して新しいスレッドで長時間実行されるCPUにバインドされた作業を開始する場合、ある時点でawait
する必要があります。では、CPUにバインドされたタスクでも、ここでasync/awaitを使用していませんか?以下の例を参照してください。
public async Task SomeMethodAsync()
{
int result = await Task.Run(() =>
{
// Do lots of CPU bound calculations...
return result;
}
// Then do something with the result.
}
async/await
は、ジョブがI/Oバウンドであるかどうかに関係なく、asyncプログラミングを行うための現代的で最も簡単な方法です。 Task
にスレッドが必要かどうか。
たとえば、メインスレッドは、子タスクでawait
を使用して、ミスピギーが1年間に昼食をとった回数を計算できるので、WinFormsやWPFに最適です(かなり長くて複雑なCPUバインド操作としましょう)。完了したら、すぐ下の次の行を実行します。これにより、従来の非同期コールバックとは異なり、コードが非常に直感的になります。 WaitOne
sまたはその他のメカニズムとそれに伴うジャグリング行為。
MSDN:
非同期プログラミングを使用することで、パフォーマンスのボトルネックを回避し、アプリケーションの全体的な応答性を向上させることができます。ただし、非同期アプリケーションを作成するための従来の手法は複雑であり、書き込み、デバッグ、保守が難しい。
Visual Studio 2012は、.NET Framework 4.5とWindowsランタイムの非同期サポートを活用する、簡素化されたアプローチである非同期プログラミングを導入しています。 コンパイラーは、開発者が使用していた困難な作業、、およびアプリケーションが同期に似た論理構造を保持しますコード。 その他...
OP:
Async/awaitがI/Oバウンドタスク用であることを何度も読みました
不正解です。 async/await
は、コンパイラーがより多くの作業を行う非同期プログラミングの省略形です。これは、I/Oに限定されたタスクだけのものではありません。 CPUバウンドタスクは通常、スレッドプールスレッドを使用します。
CPUバウンドタスクは、別のバックグラウンドスレッドで実行する必要があります。
はい...しかし、それはあなたがawait
Task
することができないという意味ではありません。 I/Oバウンドタスクとは異なり、CPUバウンドタスクは操作するためにスレッドが必要で、定義によりワーカースレッドなので、使用可能なスレッドプールから1つ取得します。
ただし、Task.Runを使用して新しいスレッドで長時間実行されるCPUにバインドされた作業を開始するときは、ある時点でそれを待つ必要があります
await
a Task
する必要はありません。そのようなタスクは「ファイアアンドフォーゲット」と呼ばれます。 await
も実際には起動せず、タスクは「ホット」です。ただし、待機しないと、アプリケーションの終了時にタスクが完了しないリスクがあります。例えばコンソールアプリがTask
を起動し、それを待たずに終了します。
では、CPUにバインドされたタスクでも、ここでasync/awaitを使用していませんか?
そうです、それはI/Oにバインドされているかどうかに関係なく、あらゆるTask
に使用できます。
何かのためにawait
した場合、その待たされた操作から結果を得るという約束があります。通常、待機中の操作は、将来実行される非同期\バックグラウンド操作であると想定しています。その間、その操作の結果とは無関係に実行できる作業を続行できます。
async/await
は、それをアーカイブするのがコンパイラの助けであることを正確に行います。 await
は、コントロールを呼び出し元に返し、待機中の操作を非同期で処理します。その非同期性は、さまざまな方法で提供できます。
I/O操作はカーネル空間に入ると非同期で処理されるため、I/O操作用に追加のスレッドを作成する必要はありません。
システムAPI呼び出しの後、要求はカーネル空間になり、OSのネットワークサブシステム(Linuxカーネルの/ netなど)に到達します。ここでは、OSはネットワーク要求を非同期で処理します。詳細は、使用するOSによって異なります(デバイスドライバーの呼び出しは、ランタイムに送り返される信号としてスケジュールされるか、デバイスドライバーの呼び出しが行われてから信号が送り返される場合があります)。ただし、最終的にはランタイムに通知されます。ネットワーク要求が進行中です。この時点で、デバイスドライバーの作業は、スケジュールされているか、進行中か、または既に完了しています(要求は既に "ネットワーク経由"で送信されています)-これはすべて非同期で行われているため、デバイスドライバーはすぐに他のものを処理してください!
一方、CPUオペレーションの場合、何らかの方法でCPUに非同期で処理を行うように指示する必要があり、通常、これは別のスレッドから実行されます(Task.Run
)。
CPUバインド非同期コードは、I/Oバインド非同期コードとは少し異なります。作業はCPUで行われるため、スレッドを計算専用にする方法はありません。 asyncとawaitを使用すると、バックグラウンドスレッドとやり取りして、asyncメソッドの呼び出し元の応答性を保つためのクリーンな方法が提供されます。これは共有データを保護しないことに注意してください。共有データを使用している場合でも、適切な同期戦略を適用する必要があります。
重要なのは、どちらの場合でも、約束が満たされるのを待つためにawait
を実行する必要があるということです。