ConcurrentDictionary AddOrUpdate'te güncelleme bölümü için eklenecekler


109

ConcurrentDictionary kullanmak için Dictionary'yi kullanarak bazı kodları yeniden yazmaya çalışıyorum. Bazı örnekleri inceledim ancak AddOrUpdate işlevini uygulamada hala sorun yaşıyorum. Bu orijinal kod:

    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;

Güncelleme kısmı için ne ekleyeceğimi bilmiyorum:

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

Herhangi bir işaretçi takdir edilecektir.

Yanıtlar:


220

Bir geçmesi gerekiyor Funcbir güncelleme durumunda sözlükte kaydedilecek değeri döndürür. Sanırım sizin durumunuzda (ekleme ve güncelleme arasında ayrım yapmadığınız için) bu şöyle olacaktır:

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

Yani, Funcher zaman sessionId döndürür, böylece hem Ekle hem de Güncelle aynı değeri ayarlar.

BTW: MSDN sayfasında bir örnek var .


4
Aynı değere eklemek veya güncellemek için bir işlev bulmak için ciddi bir şekilde mücadele ediyordum. thaks
Zapnologica

2
İyi cevap. Visual Studio'da görüntülenen AddOrUpdate () imzasından yalnızca 2 parametrenin anlamını tahmin edebilirsiniz. Ancak @ user438331'in sorduğu özel durumda, basit bir indeksleyici kullanarak cevabımdaki çözümün daha iyi olduğunu düşünüyorum.
Niklas Peter

7
@NiklasPeter'ın belirttiği gibi ( stackoverflow.com/a/32796165/8479 ), değerin üzerine yazmak için normal indeksleyiciyi kullanmanız daha iyidir, çünkü sizin durumunuzda varsa mevcut değerle ilgilenmezsiniz. Çok daha okunaklı.
Rory

3
Yanıtınızı, kullanıcıları @NiklasPeter'ın yanıtına yönlendirecek şekilde değiştirmenizi tavsiye ederim. Bu çok daha iyi bir çözüm.
Will Calderwood

63

Umarım sorunuzda hiçbir şey kaçırmamışımdır, ama neden böyle olmasın? Daha kolay, atomik ve iş parçacığı güvenlidir (aşağıya bakın).

userDic[authUser.UserId] = sessionId;

Bir anahtar / değer çiftini koşulsuz olarak sözlüğe kaydedin, anahtar zaten mevcutsa bu anahtar için herhangi bir değerin üzerine yazın: Dizin oluşturucunun ayarlayıcısını kullanın

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

İndeksleyici de atomiktir. Bunun yerine bir işlevi iletirseniz, şu olmayabilir:

Tüm bu işlemler atomiktir ve ConcurrentDictionary üzerindeki diğer tüm işlemlere göre iş parçacığı açısından güvenlidir. Her işlemin atomikliğine ilişkin tek uyarı, bir temsilci, yani AddOrUpdate ve GetOrAdd kabul edenler içindir. [...] bu delegeler kilitlerin dışında çağrılır

Bakınız: http://blogs.msdn.com/b/pfxteam/archive/2010/01/08/9945809.aspx


2
Evet atomik, çünkü bir anda oluyor ve yarısı olamaz ya da kesilemez. Bununla birlikte, bir başkasının sizden hemen önce başka bir şeye değiştirmesi güvenli değildir, bu durumda değişiklik kaybolur ve gerçekleştiğini bilmiyorsunuz, eğer değeri yalnızca beklediğiniz şeyse değiştirmek istiyorsanız o zaman bu senin için yapmayacak.
trampster

26

Bir uzantı yöntemi uyguladım:

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

İlgilenenler için şu anda, yenisini zorlamak yerine "eskiDeğer" yani mevcut değeri kullanmak için harika bir örnek olan bir vaka uyguluyorum (kişisel olarak "eski Değer" terimini sevmiyorum çünkü öyle değil sadece birkaç işlemci tik önce paralel bir iş parçacığı içinden oluşturulduğunda eskiydi).

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

6
mevcut değeri değiştirmek istemiyorsanız GetOrAdd()bunun yerine msdn.microsoft.com/en-us/library/ee378674(v=vs.110).aspx
Rory

1
Hm evet, haklısınız, GetOrAdd () bu durumda daha basit ve yeterli - bu ipucu için teşekkürler!
Nicolas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.