コンカレンシー ランタイムとその他のコンカレンシー モデルの比較
このドキュメントでは、コンカレンシー ランタイムとその他のテクノロジの機能やプログラミング モデルの違いについて説明します。 コンカレンシー ランタイムのメリットと他のプログラミング モデルのメリットの違いを理解しておくことによって、アプリケーションの要件に最も適したテクノロジを選択できます。
現在、Windows スレッド プールや OpenMP などの別のプログラミング モデルを使用している場合は、状況に応じてコンカレンシー ランタイムに移行すると効果的です。 たとえば、「Migrating from OpenMP to the Concurrency Runtime」では、OpenMP からコンカレンシー ランタイムに移行するのが適した状況について説明しています。 ただし、アプリケーションのパフォーマンスと現在のデバッグ サポートに満足している場合、移行は必要ありません。
コンカレンシー ランタイムの機能と生産性向上を通して、別のコンカレンシー モデルを使用する既存のアプリケーションを補完できます。 コンカレンシー ランタイムでは、複数のタスク スケジューラが同じコンピューティング リソースを求めて競合する場合に、負荷分散は保証されません。 ただし、作業負荷が重複しない場合、この影響はごくわずかです。
セクション
プリエンプティブ スケジューリングと協調スケジューリングの比較
プリエンプティブ モデルと協調スケジューリング モデルは、複数のタスクで、プロセッサやハードウェア スレッドなど、コンピューティング リソースを共有するための 2 つの一般的な方法です。
プリエンプティブ スケジューリングと協調スケジューリング
プリエンプティブ スケジューリング は、ラウンド ロビン方式の優先順位ベースのメカニズムで、すべてのタスクに対し、コンピューティング リソースへの排他アクセス権を所定の時間だけ与え、その後別のタスクに切り替えます。 プリエンプティブ スケジューリングは、Windows などのマルチタスク オペレーティング システムで一般的です。 "協調スケジューリング" は、すべてのタスクに対し、タスクが終了するまで、またはタスクがリソースへのアクセスを譲るまで、コンピューティング リソースへの排他アクセスを提供するメカニズムです。 コンカレンシー ランタイムは、処理リソースを最大限活用するために、協調スケジューリングを、オペレーティング システムのプリエンプティブ スケジューラと共に使用します。
プリエンプティブ スケジューラと協調スケジューラの違い
プリエンプティブ スケジューラは、複数のスレッドに対し、コンピューティング リソースへの公平なアクセス権を付与しようとすることで、すべてのスレッドを進行させます。 多くのコンピューティング リソースのあるコンピューターでは、公平なアクセスを保証すると問題は減少しますが、リソースを効率的に使用することを保証すると問題が増えます。
カーネル モードのプリエンプティブ スケジューラには、スケジュールの決定をオペレーティング システムに依存するアプリケーション コードが必要です。 これに対し、ユーザー モードの協調スケジューラでは、アプリケーション コードで独自のスケジュールを決定できます。 協調スケジューリングにより、アプリケーションは多くのスケジュールの決定を実行できるため、カーネル モードの同期に関連するオーバーヘッドが大幅に減少します。 協調スケジューラは、スケジュールする他の作業がない場合、通常はスケジュールの決定をオペレーティング システムのカーネルに委ねます。 また、カーネルに伝達されるブロック操作がある一方で、その操作がユーザー モード スケジューラに伝達されない場合にも、協調スケジューラはオペレーティング システムのスケジューラに従います。
協調スケジューリングと効率性
プリエンプティブ スケジューラにとって、同じ優先順位を持つ作業はすべて同等です。 プリエンプティブ スケジューラは、通常、作成された順序でスレッドをスケジュールします。 さらに、プリエンプティブ スケジューラは、すべてのスレッドに対し、スレッド優先順位に基づきラウンド ロビン方式でタイム スライスを与えます。 このメカニズムは公平です (すべてのスレッドが進行します) が、ある程度効率が損なわれます。 たとえば、計算量が非常に多いアルゴリズムには、公平性は不要です。 代わりに、全体の時間を最小にして関連するタスクを終了させることが重要になってきます。 協調スケジューリングにより、アプリケーションはより効率的に作業をスケジュールできます。 たとえば、多数のスレッドを使用するアプリケーションを考えてみます。 リソースを共有しないスレッドが同時に実行されるようにスケジュールすると、同期のオーバーヘッドを減少させることができ、それにより効率を向上させることができます。 タスクをスケジュールするもう 1 つの効率的な方法は、同じプロセッサでタスクのパイプラインを実行する方法です。タスクのパイプラインでは、前のタスクの出力に基づき各タスクが実行され、各パイプライン ステージの入力がメモリ キャッシュ内に事前に読み込まれます。
プリエンプティブ スケジューリングと協調スケジューリングの併用
協調スケジューリングで、スケジューリングのすべての問題が解決するわけではありません。 たとえば、他のタスクに公平に譲歩しないタスクが、使用できるすべてのコンピューティング リソースを占有し、それにより他のタスクの処理が妨げられる可能性があります。 コンカレンシー ランタイムは、協調スケジューリングの効率面での利点を使用して、プリエンプティブ スケジューリングの公平性を補完します。 既定では、コンカレンシー ランタイムで使用される協調スケジューラは、ワーク スティーリング アルゴリズムを使用して、作業をコンピューティング リソース間で効率的に分散させます。 ただし、コンカレンシー ランタイム スケジューラは、複数のアプリケーションにリソースを公平に配分するために、オペレーティング システムのプリエンプティブ スケジューラにも依存します。 また、アプリケーションでカスタム スケジューラおよびスケジューラ ポリシーを作成して、スレッドの実行を細かく制御することもできます。
[トップ]
コンカレンシー ランタイムと Windows API の比較
Microsoft Windows アプリケーション プログラミング インターフェイス (通常は Windows API と呼ばれます。以前は Win32 と呼ばれていました) は、アプリケーションでコンカレンシーを可能にするプログラミング モデルを提供します。 コンカレンシー ランタイムは、基になるオペレーティング システムから利用できない追加のプログラミング モデルを提供するために、Windows API を基に構築されています。
コンカレンシー ランタイムは、並列処理を実行する Windows API のスレッド モデルに基づいています。 また、Windows API のメモリ管理とスレッド ローカル ストレージのメカニズムも使用します。 Windows 7 および Windows Server 2008 R2 では、ユーザー スケジュール可能スレッドに関する Windows API サポート、および 64 を超えるハードウェア スレッドのあるコンピューターに関する Windows API サポートを使用します。 コンカレンシー ランタイムは、協調タスク スケジューラおよびワーク スティーリング アルゴリズムを提供してコンピューティング リソースを最大限に活用すること、および複数のスケジューラ インスタンスを同時に使用できるようにすることで、Windows API モデルを拡張します。
プログラミング言語
Windows API では、C プログラミング言語を使用して、プログラミング モデルを公開します。 コンカレンシー ランタイムでは、C++ 言語の最新機能を利用する C++ プログラミング インターフェイスを提供します。 たとえば、ラムダ関数は、並列処理関数を定義するための簡潔なタイプ セーフ メカニズムを提供します。 コンカレンシー ランタイムが使用する最新の C++ 機能の詳細については、概要に関するページを参照してください。
スレッドとスレッド プール
Windows API の中心となるコンカレンシー メカニズムはスレッドです。 通常、 CreateThread 関数を使用してスレッドを作成します。 スレッドは比較的簡単に作成して使用できますが、オペレーティング システムは、それらを管理するのに時間とその他のリソースを大量に割り当てます。 さらに、各スレッドには、同じ優先順位の他のスレッドと同じ実行時間が割り当てられることが保証されていますが、関連するオーバーヘッドのために、十分に大きいタスクを作成する必要があります。 小規模なタスクまたは詳細なタスクの場合、コンカレンシーに関連するオーバーヘッドにより、並列にタスクを実行することの利点が打ち消される可能性があります。
スレッド プールは、スレッド管理のコストを削減する方法の 1 つです。 Windows API が提供しているカスタム スレッド プールとスレッド プール実装の 2 つは、小規模な作業項目を効率的に並列で実行できるようにします。 Windows スレッド プールでは、先入れ先出し (FIFO) キューに作業項目を保持します。 各作業項目は、プールに追加された順序で開始されます。
コンカレンシー ランタイムは、ワーク スティーリング アルゴリズムを実装することで、FIFO スケジューリング メカニズムを拡張しています。 このアルゴリズムは、まだ開始されていないタスクを、作業項目が不足しているスレッドに移動します。 ワーク スティーリング アルゴリズムでは、作業負荷のバランスを取ることができますが、作業項目の順序が変更される場合もあります。 この順序変更プロセスにより、送信された順序とは異なる順序で作業項目が開始される場合があります。 これは、より古いタスク間よりも、より新しいタスク間でデータが共有される機会が多い再帰的アルゴリズムで便利です。 新しい項目を取得して最初に実行すると、キャッシュ ミスが少なくなり、場合によってはページ フォールトも少なくなります。
オペレーティング システムの視点から見ると、ワーク スティーリングは不公平です。 ただし、タスクを並列に実行するためのアルゴリズムをアプリケーションが実装している場合、サブタスク間の公平性は通常は問題になりません。 問題となるのは、タスク全体をどの程度早く終了させることができるかです。 他のアルゴリズムでは、FIFO は適切なスケジューリング方法です。
さまざまなオペレーティング システムでの動作
Windows XP および Windows Vista では、コンカレンシー ランタイムを使用するアプリケーションは同様に動作します。ただし、Windows Vista ではヒープのパフォーマンスが向上します。
Windows 7 および Windows Server 2008 R2 では、オペレーティング システムはコンカレンシーとスケーラビリティをさらにサポートしています。 たとえば、これらのオペレーティング システムは、64 を超えるハードウェア スレッドが存在するコンピューターをサポートします。 Windows API を使用する既存のアプリケーションでこれらの新しい機能を利用するには、アプリケーションを変更する必要があります。 ただし、コンカレンシー ランタイムを使用するアプリケーションは自動的にこれらの機能を使用するため、変更は必要ありません。
[トップ]
コンカレンシー ランタイムと OpenMP の比較
コンカレンシー ランタイムでは、さまざまなプログラミング モデルを使用できます。 これらのモデルは、他のライブラリのモデルと重複する場合や、他のライブラリのモデルを補完する場合があります。 このセクションでは、コンカレンシー ランタイムと OpenMPを比較します。
OpenMP プログラミング モデルは、オープン標準により定義されており、Fortran および C/C++ プログラミング言語へのバインドが適切に定義されています。 OpenMP バージョン 2.0 および 2.5 は、反復処理の並列アルゴリズムに適しています。つまり、これらは、データの配列を並列に反復処理します。 OpenMP は、並列化の度合いが事前に決定され、システムで使用可能なリソースと対応する場合に最も効果的です。 OpenMP モデルは、非常に大きい計算の問題が 1 台のコンピューターの処理リソース全体に分散される高パフォーマンスのコンピューティングに特に適しています。 このシナリオでは、ハードウェア環境が判明しており、このアルゴリズムが実行された場合、コンピューティング リソースへの排他アクセスがあることを、開発者は当然予測できます。
ただし、制約が少ないその他のコンピューティング環境は、OpenMP に適していない場合があります。 たとえば、再帰の問題 (クイックソート アルゴリズム、データ ツリーの検索など) を、OpenMP を使用して実装することはより難しくなります。 コンカレンシー ランタイムでは、並列パターン ライブラリ (PPL) や 非同期エージェント ライブラリを提供することで、OpenMP の機能を補完できます。 コンカレンシー ランタイムは、OpenMP と異なり、使用できるリソースに対応する動的スケジューラを提供しており、作業負荷の変化に応じて並列化の度合いを調整します。
コンカレンシー ランタイムの機能の多くは拡張できます。 既存の機能を組み合わせて新しい機能を作成することもできます。 OpenMP はコンパイラ ディレクティブに依存しているため、簡単には拡張できません。
コンカレンシー ランタイムと OpenMP の違いや、既存の OpenMP コードからコンカレンシー ランタイムの使用に移行する方法の詳細については、「Migrating from OpenMP to the Concurrency Runtime」を参照してください。
[トップ]