Những gì cần thêm cho phần cập nhật trong ConcurrentDictionary AddOrUpdate


109

Tôi đang cố gắng viết lại một số mã bằng Từ điển để sử dụng ConcurrentDictionary. Tôi đã xem xét một số ví dụ nhưng tôi vẫn gặp sự cố khi triển khai chức năng AddOrUpdate. Đây là mã gốc:

    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;

Tôi không biết phải thêm gì cho phần cập nhật:

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

Bất kỳ con trỏ sẽ được đánh giá cao.

Câu trả lời:


220

Bạn cần chuyển một Funcgiá trị trả về giá trị được lưu trữ trong từ điển trong trường hợp cập nhật. Tôi đoán trong trường hợp của bạn (vì bạn không phân biệt giữa thêm và cập nhật), điều này sẽ là:

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

Tức là Funcluôn trả về sessionId, để cả Thêm và Cập nhật đều đặt cùng một giá trị.

BTW: có một mẫu trên trang MSDN .


4
Tôi đã chiến đấu nghiêm túc để chỉ tìm một chức năng để thêm hoặc cập nhật cho cùng một giá trị. thaks
Zapnologica

2
Câu trả lời tốt. Chỉ từ chữ ký của AddOrUpdate () được hiển thị trong Visual Studio, bạn chỉ có thể đoán ý nghĩa của 2 tham số. Tuy nhiên, trong trường hợp cụ thể mà @ user438331 hỏi về, tôi nghĩ rằng giải pháp trong câu trả lời của tôi bằng cách sử dụng một trình chỉ mục đơn giản là tốt hơn.
Niklas Peter

7
Như @NiklasPeter đã chỉ ra ( stackoverflow.com/a/32796165/8479 ), tốt hơn hết bạn chỉ nên sử dụng trình lập chỉ mục thông thường để ghi đè giá trị, vì trong trường hợp của bạn, bạn không quan tâm đến giá trị hiện có nếu có. Dễ đọc hơn nhiều.
Rory

3
Tôi khuyên bạn nên thay đổi câu trả lời của mình để hướng người dùng đến câu trả lời của @NiklasPeter. Đó là một giải pháp tốt hơn nhiều.
Will Calderwood

63

Tôi hy vọng rằng tôi không bỏ sót bất kỳ điều gì trong câu hỏi của bạn, nhưng tại sao không chỉ như thế này? Nó dễ dàng hơn, nguyên tử và an toàn luồng (xem bên dưới).

userDic[authUser.UserId] = sessionId;

Lưu trữ một cặp khóa / giá trị vào từ điển một cách vô điều kiện, ghi đè lên bất kỳ giá trị nào cho khóa đó nếu khóa đã tồn tại: Sử dụng bộ lập chỉ mục

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

Trình chỉ mục cũng là nguyên tử. Nếu bạn chuyển một hàm thay vào đó, nó có thể không phải là:

Tất cả các hoạt động này là nguyên tử và an toàn theo chuỗi liên quan đến tất cả các hoạt động khác trên ConcurrentDictionary. Lời cảnh báo duy nhất về tính nguyên tử của mỗi hoạt động là đối với những hoạt động chấp nhận một đại diện, đó là AddOrUpdate và GetOrAdd. [...] những đại biểu này được gọi ra bên ngoài khóa

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


2
Có nguyên tử ở chỗ nó xảy ra đồng thời và một nửa không thể xảy ra hoặc bị gián đoạn. Tuy nhiên, không an toàn ở chỗ người khác có thể thay đổi nó thành thứ khác ngay trước khi bạn làm, trong trường hợp đó, thay đổi bị mất và bạn không biết điều đó đã xảy ra, nếu bạn chỉ muốn thay đổi nó nếu giá trị của bạn là như mong đợi. điều này sẽ không làm điều đó cho bạn.
trampster

26

Tôi đã kết thúc việc triển khai một phương pháp mở rộng:

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

Đối với những người quan tâm, tôi hiện đang triển khai một trường hợp là một ví dụ tuyệt vời cho việc sử dụng "oldValue" hay còn gọi là giá trị hiện có thay vì buộc một giá trị mới (cá nhân tôi không thích thuật ngữ "oldValue" vì nó không phải vậy cũ khi nó được tạo ra chỉ cách đây một vài tích tắc xử lý từ bên trong một luồng song song).

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

6
nếu bạn không muốn thay đổi giá trị hiện có, bạn nên sử dụng GetOrAdd()thay vào đó msdn.microsoft.com/en-us/library/ee378674(v=vs.110).aspx
Rory

1
Hm vâng, bạn nói đúng, GetOrAdd () đơn giản hơn và đủ trong trường hợp này - thx cho gợi ý này!
Nicolas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.