10

アプリで ConcurrentDictionary を使用したいのですが、まずそのしくみを正しく理解していることを確認する必要があります。このアプリでは、ディクショナリへの書き込みまたはディクショナリからの削除を行う 1 つ以上のスレッドを用意します。そして、ディクショナリから読み取る 1 つ以上のスレッドを用意します。潜在的に、すべて同時に。

ConcurrentDictionary の実装が、これが発生するために必要なすべてのロックを処理し、独自のロックを提供する必要がないことは正しいですか? 言い換えれば、1 つのスレッドがディクショナリへの書き込みまたはディクショナリからの削除を行っている場合、読み取りスレッド (または別の書き込みスレッド) は更新または削除が完了するまでブロックされますか?

どうもありがとう。

4

2 に答える 2

8

現在の実装では、ストライプ化されたロック (昨日、https://stackoverflow.com/a/11950835/400547で誰かへの回答で私が提案した手法) を組み合わせて使用​​し、操作によって発生する可能性がない状況について非常に懸命に考えています。同時操作の問題、またはそれによって引き起こされる問題があります (これらは非常に多くありますがそれらを使用する場合は十分に確認する必要があります)。

そのため、同時実行ディクショナリで一度に複数の操作が発生している場合、次のそれぞれが可能です。

  1. ロックするスレッドはありませんが、すべてが正しく行われます。
  2. 一部のスレッドはロックしますが、それらは別々のものをロックし、ロックの競合はありません。
  3. 1 つまたは 2 つのスレッドが互いにロックの競合を起こし、速度が低下しますが、パフォーマンスへの影響は、ロックが 1 つしかない場合よりも少なくなります。
  4. 1 つまたは 2 つのスレッドがしばらく全体をロックする必要があり (通常は内部のサイズ変更のため)、上記のケース 3 でブロックされる可能性のあるすべてのスレッドをブロックしますが、続行できるスレッドもあります (読み取るもの)。

これには、ロックに漠然と関連する問題であるダーティ リードは含まれません (私自身のコンカレント ディクショナリはロックをまったく使用せず、ダーティ リードもありません)。

このスレッド セーフは、コードによって実行されるバッチには適用されません (値を読み取ってから値を書き込むと、書き込みが完了する前に読み取られた値が変更されている可能性があります)。の呼び出しはDictionary、単一のメソッド on によって処理されますConcurrentDictionary(GetOrAddそして、アトミックに実行できるようにAddOrUpdate、 a を使用して 2 つの呼び出しになることを行いますDictionary- ただしFunc、一部のオーバーロードに関与する は複数回呼び出される可能性があることに注意してください)。

このため、 に追加の危険はないConcurrentDictionaryため、次のように選択する必要があります。

ConcurrentDictionaryたとえば、次のようなオファーと一致しない操作のバッチをロックする必要がある場合:

lock(lockObj)
{
  var test = dict[key1];
  var test2 = dict[key2];
  if(test < test2 && test2 < dict[key3] && SomeOtherBooleanProducer())
    dict[key4] = SomeFactoryCall(key4);
}

次に、 をロックする必要がConcurrentDictionaryあります。同時実行のサポートという形でそれを提供するものと組み合わせる方法があるかもしれませんが、おそらくそうではないのでDictionary、ロックで使用してください。

それ以外の場合は、おそらくどれだけの同時ヒットが発生するかということになります。ほとんどの場合、ディクショナリにヒットするスレッドは 1 つだけであるが、同時アクセスの可能性を防ぐ必要がある場合は、間違いなくDictionaryロックを使用する必要があります。半ダース以上のスレッドが辞書にヒットする期間がある場合は、間違いなく選択する必要がありConcurrentDictionaryます (同じ少数のキーにヒットする可能性が高い場合は、私のバージョンを見てください。パフォーマンスが向上する 1 つの状況)。

「少ない」スレッドと「多い」スレッドの中間点がどこにあるのかを判断するのは困難です。定期的に 2 つ以上のスレッドがある場合は、ConcurrentDictionary. 少なくとも、並行処理からの要求は、プロジェクトの存続期間を通じて、減少するよりも増加する傾向にあります。

編集:あなたが与えた特定のケースについて答えるために、1人のライターと1人のリーダーの場合、ブロックはまったくありません。これは、複数のリーダーと1人のライターが安全であるのとほぼ同じ理由で安全であるためHashtableです。ConcurrentDictionaryそれはいくつかの点で。

于 2012-08-15T14:23:47.840 に答える
6

つまり、1 つのスレッドが辞書に書き込みまたは辞書から削除している場合、読み取りスレッド (または別の書き込みスレッド) は、更新または削除が完了するまでブロックされますか?

私はそれがブロックされるとは思わない-ただ安全だろう. 破損はありません。読み取りが書き込みを認識するかどうかという点で競合が発生するだけです。

同時コレクションのロックフリー性に関する FAQから:

ConcurrentDictionary<TKey,TValue>ディクショナリ内のデータを追加または更新する際にきめの細かいロックを使用しますが、読み取り操作については完全にロックフリーです。このように、辞書からの読み取りが最も頻繁な操作であるシナリオに最適化されています。

于 2012-08-15T12:54:58.730 に答える