コンパイラエラーを修正するために、あなたはこれを行うことができます:
myDic.AddOrUpdate(1, new HashSet<int>() { myFirstElement },
(key, actualValue) => {
actualValue.Add(myFirstElement);
return actualValue;
});
しかしこれは、あなたが潜在的に複数のスレッドからではなく、スレッドセーフHashSet
に追加しているので、「更新」機能は、任意のロック内で実行されていないため、スレッドセーフではありません。これは値を失うなどの結果になる可能性があります(つまり、HashSet
に1000個のアイテムを追加しましたが、最後には970個のアイテムしかありません)。 AddOrUpdate
の更新機能には副作用があってはいけません。
あなたはHashSet
に値を追加する上で自分自身をロックすることができます
myDic.AddOrUpdate(1, new HashSet<int>() { myFirstElement },
(key, actualValue) => {
lock (actualValue) {
actualValue.Add(myFirstElement);
return actualValue;
}
});
をしかし、あなたが最初の場所でロックフリー構造(ConcurrentDictionary
)を使用している理由は、その後の質問です。それ以外にも、他のコードでは辞書からHashSet
が得られ、そこにロックをかけずに値を追加すると、すべてが役に立たなくなる可能性があります。したがって、何らかの理由でその方法に進むことに決めた場合は、その辞書からHashSet
にアクセスするときに、すべてのコードがロックされていることを確認する必要があります。
代わりに、HashSet
の代わりに並行収集を使用してください。私が知る限りConcurrentHashSet
はありませんが、別のConcurrentDictionary
をダミーキーに置き換えて使用することもできます(カスタム実装のためにインターネットを見て回ることもできます)。
サイドノート。キーが既に存在するため、その辞書が必要とされていない場合でも、AddOrUpdate
を呼び出すときにここで
myDic.AddOrUpdate(1, new Hashset<int>(){myFirstElement},
新しいHashSet
を毎回作成します。代わりに、追加の値工場でオーバーロードを使用します。
myDic.AddOrUpdate(1, (key) => new HashSet<int>() { myFirstElement },
編集:ハッシュセットとしてConcurrentDictionary
の使用例:
var myDic = new ConcurrentDictionary<long, ConcurrentDictionary<int, byte>>();
long key = 1;
int element = 1;
var hashSet = myDic.AddOrUpdate(key,
_ => new ConcurrentDictionary<int, byte>(new[] {new KeyValuePair<int, byte>(element, 0)}),
(_, oldValue) => {
oldValue.TryAdd(element, 0);
return oldValue;
});
あなたのヒントをありがとうございました。ダミーキーで値としてCouncurrentDictionaryを使用する方法の例を教えてください。ありがとう。 –
@ÁlvaroGarcía更新の回答 – Evk
の例でこの例では。私がハッシュセットを取得してから新しい要素を追加しようとすると、誰かがそれを削除する可能性があるので、追加しようとするとエラーが発生する可能性があります。または、少なくともハッシュに要素がないことを辞書に追加します。それが正しいか? –