現在の実装では、ストライプ化されたロック (昨日、https://stackoverflow.com/a/11950835/400547で誰かへの回答で私が提案した手法) を組み合わせて使用し、操作によって発生する可能性がない状況について非常に懸命に考えています。同時操作の問題、またはそれによって引き起こされる問題があります (これらは非常に多くありますが、それらを使用する場合は十分に確認する必要があります)。
そのため、同時実行ディクショナリで一度に複数の操作が発生している場合、次のそれぞれが可能です。
- ロックするスレッドはありませんが、すべてが正しく行われます。
- 一部のスレッドはロックしますが、それらは別々のものをロックし、ロックの競合はありません。
- 1 つまたは 2 つのスレッドが互いにロックの競合を起こし、速度が低下しますが、パフォーマンスへの影響は、ロックが 1 つしかない場合よりも少なくなります。
- 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
それはいくつかの点で。