29

MSDNが言うよう

ConcurrentDictionary<TKey, TValue>クラス 複数のスレッドが同時にアクセスできるキーと値のペアのスレッド セーフなコレクションを表します。

しかし、私が知っているように、System.Collections.Concurrentクラスは PLINQ 用に設計されています。

サーバーにオンラインのクライアントを保持するものがDictionary<Key,Value>あり、アクセスできるときにオブジェクトをロックすることでスレッドセーフにします。

私の場合、安全に置き換えることができますDictionary<TKey,TValue>ConcurrentDictionary<TKey,TValue>?交換したら性能は上がりますか?

この第 5 部で、Joseph Albahari は、並列プログラミング用に設計されていると述べました。

  • 並行コレクションは、並列プログラミング用に調整されています。従来のコレクションは、高度な同時実行シナリオを除くすべてのシナリオで優れています。
  • スレッド セーフなコレクションは、それを使用するコードがスレッド セーフであることを保証しません。
  • 別のスレッドがそれを変更している間に、並行コレクションを列挙しても、例外はスローされません。代わりに、古いコンテンツと新しいコンテンツが混在しています。
  • List の同時バージョンはありません。
  • 並行スタック、キュー、およびバッグ クラスは、リンクされたリストを使用して内部的に実装されます。これにより、非並行の Stack および Queue クラスよりもメモリ効率が低下しますが、リンク リストはロックフリーまたは低ロックの実装に役立つため、並行アクセスには適しています。(これは、リンクされたリストにノードを挿入するには、いくつかの参照を更新するだけで済みますが、リストのような構造に要素を挿入するには、何千もの既存の要素を移動する必要がある場合があるためです。)
4

5 に答える 5

19

あなたがロック内で何をしているのかをもっと知らなければ、言うことは不可能です。

たとえば、すべての辞書アクセスが次のようになっている場合:

lock(lockObject)
{
    foo = dict[key];
}

... // elsewhere

lock(lockObject)
{
    dict[key] = foo;
}

そうすれば、問題なく切り替えることができます(ただし、パフォーマンスに違いは見られない可能性が高いため、壊れていない場合は修正しないでください)。ただし、辞書を操作するロックブロック内で何か凝ったことをしている場合は、辞書がロックブロック内で行っていることを実行できる単一の関数を提供していることを確認する必要があります。以前とは機能的に異なるコードになってしまいます。覚えておくべき最大のことは、ディクショナリは、ディクショナリへの同時呼び出しがシリアル方式で実行されることのみを保証することです。コード内に辞書と複数回相互作用する単一のアクションがある場合は処理できません。そのような場合、ConcurrentDictionary、独自の同時実行制御が必要です。

ありがたいことに、はやなどのConcurrentDictionaryより一般的なマルチステップ操作のためのいくつかのヘルパー関数を提供しますAddOrUpdateGetOrAdd、すべての状況をカバーできるわけではありません。ロジックをこれらの関数に組み込むために作業する必要がある場合は、独自の並行性を処理する方がよい場合があります。

于 2011-03-14T19:37:14.047 に答える
5

に置き換えるほど簡単でDictionaryConcurrentDictionaryありません。これらのクラスには、スレッドセーフを保証するために、異なる動作をする新しいメソッドがあるため、コードを調整する必要があります。

Addたとえば、 orを呼び出す代わりに、 andRemoveTryAddありTryRemoveます。アトミックに動作するこれらのメソッドを使用することが重要ですlock.

于 2011-03-14T19:40:19.867 に答える
1

に置き換えることができDictionary<TKey, TValue>ますConcurrentDictionary<TKey, TValue>

ただし、パフォーマンスへの影響は希望どおりではない場合があります(ロック/同期が多い場合、パフォーマンスが低下する可能性があります...ただし、少なくともコレクションはスレッドセーフです)。

于 2011-03-14T19:35:46.547 に答える
1

置換の難しさについてはわかりませんが、同じ「ロックセッション」で辞書内の複数の要素にアクセスする必要がある場所がある場合は、コードを変更する必要があります。

読み取り操作が他の読み取り操作をブロックしてはならないため、Microsoftが読み取りと書き込みに別々のロックを指定している場合は、パフォーマンスが向上する可能性があります。

于 2011-03-14T19:36:18.640 に答える
0

はい、安全に置き換えることができますが、plinq 用に設計されたディクショナリには、使用できない追加機能用の余分なコードが含まれている場合があります。ただし、パフォーマンスのオーバーヘッドはわずかに非常に小さくなります。

于 2011-03-14T19:37:48.603 に答える