2017-10-31 6 views
2

필자는 ConcurrentDictionary에 int 형의 long 값과 long 값을 가지는 키를 가지고 있습니다. 키가 사전에 없으면 첫 번째 요소가있는 새 해시 세트를 추가합니다. 키가 있으면 기존 요소에 새 요소를 추가하십시오. .Add() 메소드는 부울을 반환하고 AddOrUpdate가 HashSet의 기대 때문에,ConcurrentDictionary의 값인 새 요소를 해시 집합에 추가하는 방법?

ConcurrentDictionary<long, HashSet<int>> myDic = new ConcurrentDictionary<long, HashSet<int>>(); 
int myElement = 1; 
myDic.AddOrUpdate(1, new Hashset<int>(){myFirstElement}, 
(key, actualValue) => actualValue.Add(myElement)); 

이 코드의 문제는 세 번째 매개 변수입니다 :

나는 그런 일을하려합니다. 첫 번째와 두 번째 매개 변수가 맞습니다.

그래서 내 질문에 스레드 안전 방법으로 해시 세트에 새로운 요소를 추가하고 중복을 피할 수있다. (그것이 내가 해시 값을 값으로 사용하는 이유이다). 해시셋의 문제는 스레드로부터 안전하지 않으며, 먼저 가져 와서 나중에 새 요소를 추가하면 사전 밖에 있고 문제가있을 수 있다는 것입니다.

감사합니다. 당신이 중괄호의 익명 함수 정의를 포장하는 경우

답변

3

당신이 할 수있는 컴파일러 오류를 수정하기를 : 당신이 잠재적으로하지 스레드 안전 여러 스레드에서 HashSet에 추가 할 수 있도록 "업데이트"기능은 어떤 잠금 내에서 실행되지 않기 때문에

myDic.AddOrUpdate(1, new HashSet<int>() { myFirstElement }, 
    (key, actualValue) => { 
     actualValue.Add(myFirstElement); 
     return actualValue; 
    }); 

하지만이, 스레드로부터 안전하지 않습니다. 예를 들어 값이 손실 될 수 있습니다. 따라서 HashSet에 1000 개의 항목을 추가했지만 결국에는 970 개의 항목 만 남았습니다. AddOrUpdate의 업데이트 기능에는 부작용이 없어야하며 여기에 설명되어 있습니다.

myDic.AddOrUpdate(1, new HashSet<int>() { myFirstElement }, 
    (key, actualValue) => { 
     lock (actualValue) { 
      actualValue.Add(myFirstElement); 
      return actualValue; 
     } 
    }); 

를하지만 처음에 잠금이없는 구조 (ConcurrentDictionary)를 사용하는 이유는 다음 질문은

당신은 HashSet에 값을 추가하는 자신을 통해 잠글 수 있습니다. 게다가 다른 코드는 사전에서 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; 
    }); 
+0

이 팁 주셔서 너무 감사드립니다. 예를 들어, 더미 키를 사용하여 CouncurrentDictionary를 값으로 사용할 수있는 방법을 보여줄 수 있습니까? 감사. –

+0

@ ÁlvaroGarcía 업데이트 대답 예 – Evk

+0

이 예제에서. 내가 해시 세트를 얻고 새 요소를 추가하려고하면 누군가가이를 삭제할 수 있으므로 추가하려고 할 때 오류가 발생할 수 있습니다. 또는 최소한 사전에없는 해트트에 요소를 추가합니다. . 맞습니까? –

1

, 당신은 함수의 본문에서 여러 문을 정의하고, 따라서이 같은 반환 값을 지정할 수 있습니다

myDic.AddOrUpdate(1, new HashSet<int>() { myFirstElement }, 
(key, actualValue) => { 
    actualValue.Add(myElement); 
    return actualValue; 
});