동시 사전 올바른 사용법


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

3
myDic[InputID]경합 상태 에 대해 키로 직접 액세스하는 것을 피해야합니다 . 시도해야합니다GetOrAdd
Olivier Albertini 2016 년

3
@OlivierAlbertini, myDic[InputID]lvalue로 사용할 때 문제가 발생 하지 않는다고 생각 합니다. GetOrAdd값이 존재하지 않는 경우에만 추가되므로 올바른 대체가 아닙니다. 대신 AddOrUpdate사전에 동일한 값을 추가 / 업데이트 하는 데 사용할 수 있습니다.
Jatin Sanghvi

답변:


75

스레드 안전성이 의미하는 바에 따라 다릅니다.

MSDN에서- 방법 : ConcurrentDictionary에서 항목 추가 및 제거 :

ConcurrentDictionary<TKey, TValue>다중 스레드 시나리오를 위해 설계되었습니다. 컬렉션에서 항목을 추가하거나 제거하기 위해 코드에서 잠금을 사용할 필요가 없습니다. 그러나 한 스레드는 항상 값을 검색하고 다른 스레드는 동일한 키에 새 값을 제공하여 컬렉션을 즉시 업데이트 할 수 있습니다.

따라서 사전에있는 항목의 값에 대한 일관성없는 보기 를 얻을 수 있습니다 .


2
흥미로운 점입니다! 이 시나리오에서 여전히 자물쇠를 사용 하시겠습니까?
Jon

@Jon-그것은 당신의 응용 프로그램과 괜찮은지 여부에 따라 다릅니다. 그러나 항목에 대한 일관된보기를 원한다면 항목의 각 읽기 및 업데이트를 잠금으로 래핑해야합니다.
Oded

12
나는 이것이 의사가 말하는 것이 아니라고 생각합니다. 불일치는 뷰에 포함 된 내용과 관련이 있습니다. 뷰가 값일 경우 완벽하게 일치합니다. 키 값을 얻는 한 사전의 키 값이 변경 될 수 있습니다. 이것은 DateTime.Now 값만큼 일치하지 않습니다.
George Mavritsakis 2014-06-20

4

이것을 찾는 가장 좋은 방법은 MSDN 문서를 확인하는 것입니다.

ConcurrentDictionary의 경우 페이지는 http://msdn.microsoft.com/en-us/library/dd287191.aspx 입니다 .

스레드 안전 섹션에는 "ConcurrentDictionary (Of TKey, TValue)의 모든 공용 및 보호 멤버는 스레드로부터 안전하며 여러 스레드에서 동시에 사용할 수 있습니다."라고 명시되어 있습니다.

따라서 동시성 관점에서 보면 괜찮습니다.


2

그래 네가 맞아.

그것과 한 스레드에서 사전을 열거하고 다른 스레드에서 변경하는 가능성은 해당 클래스의 유일한 존재 수단입니다.


9
내가 추가하고 싶은 것은 여기ConcurrentDictionary.
alex.b

1

제 경우에는이 방법을 선호합니다.

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

메서드 사용에 대한 자세한 내용은 MSDN Library 를 참조 하십시오.

샘플 사용법 :

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

예를 들어 이전에 추가 한 객체의 속성을 변경하기 위해 저장된 객체를 완전히 변경하지 않고 내용을 업데이트해야하는 경우이 방법이 유용합니다. 그렇지 않으면 잠금 또는 기타 동기화 방법을 사용해야합니다.
Onur

1

참고 사항 : 선형 루프가 있는 ConcurrentDicitonary 객체를 사용하는 것을 정당화하지 않아 활용도가 떨어집니다. 가장 좋은 대안은 아래 예제에 따라 Oded가 Parallelism을 사용하여 언급 한대로 Microsoft 설명서의 권장 사항을 따르는 것입니다 .

Parallel.For(0, 4, i => 
{
   myDic.TryAdd(i, 0);
});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.