並行辞書正しい使用法


84

私はこれが並行辞書の正しい使用法であると考えるのは正しいですか

private ConcurrentDictionary<int,long> myDic = new ConcurrentDictionary<int,long>();

//Main thread at program startup

for(int i = 0; i < 4; i++)
{
  myDic.Add(i, 0);
}

//Seperate threads use this to update a value

myDic[InputID] = newLongValue;

ロックなどがなく、複数のスレッドが同じことを行おうとしている場合でも、辞書の値を更新しているだけです。


2
それは依存します-newLongValue以前の値に依存しmyDic[InputID]ますか?
damien_The_Unbeliever 2011

3
myDic[InputID]競合状態のために、キーから直接アクセスすることは避けてください。試してみてくださいGetOrAdd
オリビエアルベルティーニ2016

3
@OlivierAlbertini、myDic[InputID]左辺値として使用しても問題はないと思います。GetOrAdd値が存在しない場合にのみ追加されるため、正しい置換ではありません。代わりにAddOrUpdate、辞書で同じ値を追加/更新するために使用できます。
Jatin Sanghvi 2017

回答:


75

スレッドセーフの意味によって異なります。

MSDNから-方法:ConcurrentDictionaryからアイテムを追加および削除する

ConcurrentDictionary<TKey, TValue>マルチスレッドシナリオ用に設計されています。コレクションにアイテムを追加したり、コレクションからアイテムを削除したりするために、コードでロックを使用する必要はありません。ただし、1つのスレッドが値を取得し、別のスレッドが同じキーに新しい値を与えることでコレクションをすぐに更新することは常に可能です。

そのため、ディクショナリ内のアイテムの値について一貫性のないビューを取得する可能性があります。


2
それは興味深い点です!そのシナリオでもロックを使用しますか?
ジョン

@ Jon-それはあなたのアプリケーションとそれが大丈夫かどうかに依存します。ただし、アイテムの一貫したビューが必要な場合は、アイテムの読み取りと更新のたびにロックでラップする必要があります。
2011

12
私はこれがドキュメントが言っていることではないと思います。不整合は、ビューに含まれる内容と関係があります。ビューが単なる値である場合、完全に整合性があります。キーの値を取得している限り、ディクショナリ内のキーの値は変更される可能性があります。これは、DateTime.Now値と同じくらい一貫性がありません。
George Mavritsakis 2014年

4

これを見つける最良の方法は、MSDNのドキュメントを確認することです。

ConcurrentDictionaryの場合、ページはhttp://msdn.microsoft.com/en-us/library/dd287191.aspxです

スレッドセーフのセクションでは、「ConcurrentDictionary(Of TKey、TValue)のすべてのパブリックメンバーと保護されたメンバーはスレッドセーフであり、複数のスレッドから同時に使用できます」と記載されています。

したがって、同時実行の観点からは大丈夫です。


2

はい、その通りです。

それと、あるスレッドで辞書を列挙し、別のスレッドで辞書を変更する可能性は、そのクラスが存在する唯一の手段です。


9
追加したいのは、ここにをいつどのように使用するかについての役立つ情報があるということConcurrentDictionaryです。
alex.b 2011

1

私の場合、この方法を使用することを好みます。

ConcurrentDictionary<TKey, TValue>.AddOrUpdate Method (TKey, Func<TKey, TValue>, Func<TKey, TValue, TValue>);

参照してください。MSDNライブラリのメソッドの使用方法の詳細については。

使用例:

results.AddOrUpdate(
  Id,
  id => new DbResult() {
     Id = id,
     Value = row.Value,
     Rank = 1
  },
  (id, v) =>
  {
     v.Rank++;
     return v;
  });

2
参考:「値ファクトリメソッドを(GetOrAddメソッドとAddOrUpdateメソッドに)指定すると、実際に実行され、後で結果が破棄される可能性があります(他のスレッドがレースに勝ったため)。」詳細:arbel.net/2013/02/03/...
keremispirli

はい、その通りです。備考セクションに記載されているように、「異なるスレッドでAddOrUpdateを同時に呼び出すと、addValueFactoryが複数回呼び出される可能性がありますが、そのキーと値のペアがすべての呼び出しでディクショナリに追加されるとは限りません。」したがって、複数の永続オブジェクトを生成していないことを確認する必要があります。
Onur 2016

また、以前に追加したオブジェクトのプロパティを変更するなど、保存されたオブジェクトを完全に変更するのではなく、コンテンツを更新する必要がある場合は、このメソッドが役立ちます。それ以外の場合は、ロックまたは他の同期メソッドを使用する必要があります。
Onur 2016

1

注:線形ループでConcurrentDicitonaryオブジェクトを使用することは正当化されないため、十分に活用されていません。最良の代替策は、以下の例に従って、並列処理を使用してOdedが述べたように、Microsoftドキュメントの推奨事項に従うことです。

Parallel.For(0, 4, i => 
{
   myDic.TryAdd(i, 0);
});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.