並列プログラミングのデータ構造
.NET Framework Version 4 では、並列プログラミングに役立つ新しい型がいくつか導入されています。たとえば、一連の同時実行コレクション クラス、軽量な同期プリミティブ、限定的な初期化などです。 これらの型は、タスク並列ライブラリや PLINQ などのマルチスレッド アプリケーション コードで使用できます。
同時実行コレクション クラス
System.Collections.Concurrent 名前空間のコレクション クラスには、スレッド セーフな追加操作と削除操作が用意されており、できる限りロックを回避する一方で、ロックが必要な場合は粒度の細かいロックを使用できます。 .NET Framework Version 1.0 および 2.0 で導入されたコレクションとは異なり、同時実行コレクション クラスでは、項目にアクセスするときにロックを取得するユーザー コードを必要としません。 同時実行コレクション クラスでは、複数のスレッドが 1 つのコレクションに項目を追加したり、コレクションから項目を削除したりする場合に、System.Collections.ArrayList、System.Collections.Generic.List<T> などの型で (ユーザーが実装したロックを使用して) パフォーマンスを大幅に向上させることができます。
次の表は、新しい同時実行コレクション クラスの一覧です。
型 |
説明 |
---|---|
System.Collections.Concurrent.IProducerConsumerCollection<T> を実装するスレッド セーフなコレクションに、ブロッキングと範囲指定の機能を提供します。 スロットが使用できないか、コレクションがいっぱいになった場合に、producer スレッドがブロックを実行します。 コレクションが空の場合、consumer スレッドがブロックを実行します。 また、この型は consumer と producer によってブロックされないアクセスもサポートしています。 BlockingCollection<T> は、IEnumerable<T> をサポートするコレクション クラスにブロッキングおよび境界を提供する基本クラスまたはバッキング ストアとして使用できます。 |
|
スケーラブルな操作の追加と取得を提供するスレッド セーフなバッグの実装。 |
|
System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> |
同時実行されるスケーラブルなディクショナリ型。 |
同時実行されるスケーラブルな FIFO キュー。 |
|
同時実行されるスケーラブルな LIFO スタック。 |
詳細については、「スレッド セーフなコレクション」を参照してください。
同期プリミティブ
従来のマルチスレッド コードに見られる負荷の高いロック機構を使用する代わりに System.Threading 名前空間の新しい同期プリミティブを使用すると、粒度の細かい同時実行とパフォーマンスの向上が実現されます。 System.Threading.Barrier、System.Threading.CountdownEvent などの新しい型の場合、.NET Framework の以前のリリースには同等の型がありません。
新しい同期型の一覧を次に示します。
型 |
説明 |
---|---|
各タスクが到着を通知してから一部またはすべてのタスクが到着するまでブロックするポイントを指定して、複数のスレッドが並列のアルゴリズムで実行できるようにします。 詳細については、「バリア (.NET Framework)」を参照してください。 |
|
容易な連結方法を提供して、フォークと結合の方法を簡略化します。 詳細については、「CountdownEvent」を参照してください。 |
|
System.Threading.ManualResetEvent に似た同期プリミティブです。 ManualResetEventSlim は軽量ですが、プロセス間通信での使用に限定されます。 詳細については、「ManualResetEvent と ManualResetEventSlim」を参照してください。 |
|
リソースまたはリソースのプールに同時にアクセスできるスレッドの数を制限する同期プリミティブです。 詳細については、「Semaphore と SemaphoreSlim」を参照してください。 |
|
クォンタムを生成するまでの一定期間内に、ループまたはスピンで待機するロックの取得を試みるスレッドを発生させるロック プリミティブで、一度に 1 つしか指定できません。 ロックの待機時間が短いことが予測される場合、SpinLock ではその他の形式のロックよりも高いパフォーマンスが得られます。 詳細については、「SpinLock」を参照してください。 |
|
指定された時刻にスピンし、スピン カウントが超過した場合は最終的にスレッドを待機状態にする、小さくて軽量な型です。 詳細については、「SpinWait」を参照してください。 |
詳細については、次のトピックを参照してください。
限定的な初期化クラス
限定的な初期化を使用すると、オブジェクトのメモリは必要になるまで割り当てられません。 限定的な初期化では、プログラムの有効期間内でオブジェクトの割り当てを均等に展開することによって、パフォーマンスが向上します。 Lazy<T> の型をラップすることにより、任意のカスタム型の限定的な初期化を有効にできます。
限定的な初期化の型の一覧を次に示します。
型 |
説明 |
---|---|
軽量でスレッド セーフな限定的な初期化を提供します。 |
|
初期化関数を限定的に呼び出す各スレッドで、スレッドごとに限定的に初期化された値を提供します。 |
|
専用の限定的な初期化インスタンスを割り当てる必要を回避する静的メソッドを提供します。 代わりに、参照を使用して、ターゲットがアクセスされるときに初期化されていることを確認します。 |
詳細については、「限定的な初期化」を参照してください。
例外の集約
System.AggregateException 型を使用して、別のスレッドで同時にスローされた複数の例外をキャプチャし、単一の例外として連結しているスレッドに返すことができます。 System.Threading.Tasks.Task 型、System.Threading.Tasks.Parallel 型、および PLINQ は、この目的で幅広く AggregateException を使用します。 詳細については、「方法: タスクがスローした例外を処理する」および「方法: PLINQ クエリの例外を処理する」を参照してください。