ConcurrentDictionary AddOrUpdate에서 업데이트 부분에 추가 할 항목


109

ConcurrentDictionary를 사용하기 위해 Dictionary를 사용하여 일부 코드를 다시 작성하려고합니다. 몇 가지 예를 검토했지만 여전히 AddOrUpdate 기능을 구현하는 데 문제가 있습니다. 이것은 원래 코드입니다.

    dynamic a = HttpContext;
    Dictionary<int, string> userDic = this.HttpContext.Application["UserSessionList"] as Dictionary<int, String>;

   if (userDic != null)
   {
      if (useDic.ContainsKey(authUser.UserId))
      {
        userDic.Remove(authUser.UserId);
      }
   }
  else
  {
     userDic = new Dictionary<int,string>();
  }
  userDic.Add(authUser.UserId, a.Session.SessionID.ToString());
  this.HttpContext.Application["UserDic"] = userDic;

업데이트 부분에 무엇을 추가해야할지 모르겠습니다.

userDic.AddOrUpdate(authUser.UserId,
                    a.Session.SessionID.ToString(),
                    /*** what to add here? ***/);

모든 포인터를 주시면 감사하겠습니다.

답변:


220

Func업데이트시 사전에 저장할 값을 반환 하는를 전달해야합니다 . 귀하의 경우 (추가와 업데이트를 구별하지 않기 때문에) 이것은 다음과 같습니다.

var sessionId = a.Session.SessionID.ToString();
userDic.AddOrUpdate(
  authUser.UserId,
  sessionId,
  (key, oldValue) => sessionId);

즉, Func항상 sessionId를 반환하므로 Add와 Update가 동일한 값을 설정합니다.

BTW : MSDN 페이지 에 샘플이 있습니다.


4
동일한 값에 추가하거나 업데이트 할 함수를 찾기 위해 진지하게 싸우고있었습니다. thaks
Zapnologica 2014

2
좋은 대답입니다. Visual Studio에 표시된 AddOrUpdate ()의 서명만으로는 두 매개 변수의 의미 만 추측 할 수 있습니다. 그러나 @ user438331이 묻는 특정 경우에는 간단한 인덱서를 사용하는 내 대답의 솔루션이 더 낫다고 생각합니다.
Niklas Peter

7
@NiklasPeter가 지적했듯이 ( stackoverflow.com/a/32796165/8479 ), 귀하의 경우 기존 값에 관심이 없기 때문에 일반 인덱서를 사용하여 값을 덮어 쓰는 것이 좋습니다. 훨씬 더 읽기 쉽습니다.
Rory

3
@NiklasPeter의 답변에서 사용자를 가리 키도록 답변을 변경하는 것이 좋습니다. 훨씬 더 나은 솔루션입니다.
Will Calderwood

63

나는 당신의 질문에서 아무것도 놓치지 않았기를 바랍니다. 그러나 왜 이렇게하지 않습니까? 더 쉽고 원자 적이며 스레드로부터 안전합니다 (아래 참조).

userDic[authUser.UserId] = sessionId;

키 / 값 쌍을 사전에 무조건 사전에 저장하고 키가 이미있는 경우 해당 키의 값을 덮어 씁니다. 인덱서의 setter를 사용합니다.

(참조 : http://blogs.msdn.com/b/pfxteam/archive/2010/01/08/9945809.aspx )

인덱서도 원자 적입니다. 대신 함수를 전달하면 다음과 같지 않을 수 있습니다.

이러한 모든 작업은 원자 적이며 ConcurrentDictionary의 다른 모든 작업과 관련하여 스레드로부터 안전합니다. 각 작업의 원자성에 대한 유일한주의 사항은 AddOrUpdate 및 GetOrAdd와 같은 대리자를 허용하는 작업에 대한 것입니다. [...] 이러한 위임은 잠금 외부에서 호출됩니다.

참조 : http://blogs.msdn.com/b/pfxteam/archive/2010/01/08/9945809.aspx


2
네 원자는 한꺼번에 일어나고 반이 일어나거나 중단 될 수 없다는 점에서 그렇습니다. 그러나 다른 사람이 당신이하기 직전에 다른 것으로 변경할 수 있다는 점에서 안전하지 않습니다.이 경우 변경 사항이 손실되고 그 값이 예상 한 값인 경우에만 변경하려는 경우 발생했는지 알 수 없습니다. 이것은 당신을 위해 그렇게하지 않을 것입니다.
trampster

26

결국 확장 메서드를 구현했습니다.

static class ExtensionMethods
{
    // Either Add or overwrite
    public static void AddOrUpdate<K, V>(this ConcurrentDictionary<K, V> dictionary, K key, V value)
    {
        dictionary.AddOrUpdate(key, value, (oldkey, oldvalue) => value);
    }
}

1

관심이있는 사람들을 위해 저는 현재 새로운 값을 강요하는 대신 "oldValue"일명 기존 값을 사용하는 좋은 예를 구현하고 있습니다. (개인적으로 "oldValue"라는 용어는 그렇지 않습니다. 병렬 스레드 내에서 몇 프로세서 틱 전에 생성되었을 때).

dictionaryCacheQueues.AddOrUpdate(
    uid,
    new ConcurrentQueue<T>(),
    (existingUid, existingValue) => existingValue
);

6
기존 값을 변경하지 않으려면 사용해야 GetOrAdd()하는 대신 msdn.microsoft.com/en-us/library/ee378674(v=vs.110).aspx
로리

1
네, 맞습니다.이 경우 GetOrAdd ()가 더 간단하고 충분합니다.
Nicolas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.