Microsoftの非同期アプローチは、マルチスレッドプログラミングの最も一般的な目的(IOタスクに対する応答性の向上)に代わるものです。
ただし、非同期アプローチでは、パフォーマンスをまったく向上させることも、CPUを集中的に使用するタスクに対する応答性を向上させることもできないことを認識することが重要です。
応答性のためのマルチスレッド
応答性のためのマルチスレッドは、重いIOタスクまたは重い計算タスク中にプログラムの応答性を維持する従来の方法です。バックグラウンドスレッドにファイルを保存すると、ユーザーはハードドライブがタスクを完了するのを待たずに作業を続行できます。IOスレッドは多くの場合、書き込みの一部が終了するのを待機してブロックするため、コンテキストの切り替えが頻繁に発生します。
同様に、複雑な計算を実行する場合、UIの応答性を維持し、ユーザーがプログラムがクラッシュしたとは思わないように、通常のコンテキストスイッチングを許可する必要があります。
ここでの目標は、一般に、複数のスレッドを異なるCPUで実行することではありません。代わりに、バックグラウンドタスクの実行中にUIが更新されてユーザーに応答できるように、長時間実行されるバックグラウンドタスクとUIの間でコンテキストスイッチが発生することに関心があります。一般的に、UIは多くのCPUパワーを消費せず、スレッドフレームワークまたはOSは通常、それらを同じCPUで実行することを決定します。
コンテキストの切り替えに余分なコストがかかるため、実際には全体的なパフォーマンスが低下しますが、CPUのパフォーマンスが目標ではなかったため、気にしません。通常、必要以上のCPUパワーを持っていることがわかっているため、マルチスレッドに関する目標は、ユーザーの時間を無駄にすることなく、ユーザーのタスクを完了させることです。
「非同期」の代替
「非同期アプローチ」は、単一のスレッド内でコンテキストスイッチを有効にすることにより、この状況を変化させます。これにより、すべてのタスクが単一のCPUで実行されることが保証され、スレッドの作成/クリーンアップが少なくなり、スレッド間の実際のコンテキスト切り替えが少なくなるという点で、パフォーマンスが若干向上します。
ネットワークリソースの受信を待機する新しいスレッドを作成する代わりに(イメージのダウンロードなど)、async
メソッドが使用されます。これawait
により、イメージが利用可能になり、その間、呼び出し元のメソッドに譲ります。
ここでの主な利点は、ロックと同期をまったく使用していないため、デッドロックを回避するなどのスレッドの問題を心配する必要がなく、プログラマーがバックグラウンドスレッドを設定して戻ってくる作業が少し少ないことです。 UIを安全に更新するために、結果が戻ったときにUIスレッドで。
技術的な詳細をあまり深く見ていませんが、時々のCPUアクティビティが少ないダウンロードを管理することは、個別のスレッドではなく、UIイベントキューのタスクのようなものになり、ダウンロードが完了すると、非同期メソッドがそのイベントキューから再開されます。つまり、await
「必要な結果が利用可能かどうかを確認し、利用できない場合は、このスレッドのタスクキューに戻してください」という意味です。
このアプローチはCPU集中型タスクの問題を解決しないことに注意してください。待機するデータがないため、実際のバックグラウンドワーカースレッドを作成せずにコンテキストスイッチを取得することはできません。もちろん、非同期アプローチを広く使用しているプログラムでは、非同期メソッドを使用してバックグラウンドスレッドを開始し、結果を返すと便利な場合があります。
パフォーマンスのためのマルチスレッド
「パフォーマンス」について説明しているので、パフォーマンス向上のためにマルチスレッドを使用する方法についても説明したいと思います。これは、シングルスレッドの非同期アプローチではまったく不可能なことです。
実際に、単一のCPUで十分なCPU能力を持っていない状況にあり、パフォーマンスのためにマルチスレッドを使用したい場合、実際に実行するのは難しいことがよくあります。一方、1つのCPUで十分な処理能力がない場合、それは多くの場合、プログラムが合理的な時間枠で達成したいことを実行できるようにする唯一のソリューションであり、これが作業を価値のあるものにします。
自明な並列処理
もちろん、場合によっては、マルチスレッドから実際のスピードアップを簡単に得ることができます。
多数の独立した計算集約タスク(つまり、結果を決定するために実行する必要がある計算に関して入力データと出力データが非常に小さいタスク)が発生した場合、多くの場合、大幅な高速化を実現できます。スレッドのプール(使用可能なCPUの数に基づいて適切なサイズ)を作成し、マスタースレッドに作業を分散させて結果を収集します。
パフォーマンスのための実用的なマルチスレッド
私はあまり専門家になりたくはありませんが、私の印象では、一般的に、最近行われているパフォーマンスのための最も実用的なマルチスレッドは、些細な並列性を持つアプリケーション内の場所を探し、複数のスレッドを使用することです利益を享受するために。
最適化と同様に、通常はプログラムのパフォーマンスをプロファイルし、ホットスポットを特定した後に最適化することをお勧めします。この部分をあるスレッドで実行し、その部分を別のスレッドで実行することを任意に決定することで、プログラムをスローダウンするのは簡単です最初に、両方の部分がCPU時間のかなりの部分を占めているかどうかを判断します。
スレッドが増えると、セットアップ/ティアダウンのコストが増加し、コンテキストの切り替えまたはCPU間の通信コストが増加します。別個のCPU上にある場合、それらのコストを補うのに十分な作業を行っておらず、応答性の理由で別個のスレッドである必要がない場合、速度は低下します。
相互依存性がほとんどなく、プログラムのランタイムの大部分を占めているタスクを探します。
それらに相互依存性がない場合、それは些細な並列性の場合であり、スレッドで簡単にセットアップして利点を享受できます。
相互依存性が制限されているタスクを見つけることができ、情報を交換するためのロックと同期によってタスクの速度が大幅に低下しない場合、同期時または誤ったロジックによるデッドロックの危険を回避するために注意を払うと、マルチスレッドによってある程度の速度向上が得られます必要なときに同期しないため、誤った結果になります。
あるいは、マルチスレッドのより一般的なアプリケーションのいくつかは、(ある意味では)所定のアルゴリズムの高速化を求めていませんが、代わりに、彼らが書く予定のアルゴリズムのより大きな予算を求めています:ゲームエンジンを書いている場合、AIはフレームレート内で決定する必要があるため、独自のCPUを使用できる場合は、AIにより多くのCPUサイクルバジェットを割り当てることができます。
ただし、スレッドのプロファイルを作成し、ある時点でコストを補うのに十分な作業を行っていることを確認してください。
並列アルゴリズム
また、複数のプロセッサを使用して高速化できる多くの問題がありますが、それらは単純すぎてCPU間で分割できません。
並列アルゴリズムは、複数のCPUを使用することによるメリットを排除するためにCPU間通信コストが非常に簡単であるため、利用可能な最良の非並列アルゴリズムに関して、big-Oランタイムについて慎重に分析する必要があります。一般に、各CPUで計算を使用するよりも、CPU間通信(big-O用語)を少なくする必要があります。
現時点では、複雑な分析が必要なため、一部には些細な並列処理が非常に一般的であるため、一部にはコンピューターにあまり多くのCPUコアがないため、学術研究のためのスペースです1つのCPUで妥当な時間枠で解決できない場合は、すべてのCPUを使用して妥当な時間枠で解決できます。