Cách sử dụng đúng từ điển đồng thời


84

Tôi có đúng khi nghĩ rằng đây là cách sử dụng chính xác Từ điển Đồng thời

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;

Tôi không có khóa, v.v. và chỉ đang cập nhật giá trị trong từ điển mặc dù nhiều chủ đề có thể đang cố gắng làm như vậy.


2
Nó phụ thuộc - không newLongValuephụ thuộc vào giá trị trước đó của myDic[InputID]?
Damien_The_Un Believer

3
bạn nên tránh truy cập bằng khóa trực tiếp myDic[InputID]cho tình trạng cuộc đua. Bạn nên thửGetOrAdd
Olivier Albertini

3
@OlivierAlbertini, tôi không nghĩ myDic[InputID]gây ra bất kỳ vấn đề gì khi nó được sử dụng làm giá trị. GetOrAddkhông phải là sự thay thế chính xác vì nó chỉ thêm vào nếu giá trị không tồn tại. Thay vào đó, chúng ta có thể sử dụng AddOrUpdateđể thêm / cập nhật cùng một giá trị trong từ điển.
Jatin Sanghvi

Câu trả lời:


75

Nó phụ thuộc vào những gì bạn có nghĩa là an toàn luồng.

Từ MSDN - Cách: Thêm và Xóa các Mục khỏi Đồng thờiDictionary :

ConcurrentDictionary<TKey, TValue>được thiết kế cho các kịch bản đa luồng. Bạn không phải sử dụng khóa trong mã của mình để thêm hoặc xóa các mục khỏi bộ sưu tập. Tuy nhiên, luôn có khả năng một luồng lấy một giá trị và một luồng khác cập nhật ngay tập hợp bằng cách đặt cho cùng một khóa một giá trị mới.

Vì vậy, có thể có một cái nhìn không nhất quán về giá trị của một mục trong từ điển.


2
Đó là một điểm thú vị! Bạn sẽ vẫn sử dụng một khóa trong trường hợp đó?
Jon

@Jon - Nó phụ thuộc vào ứng dụng của bạn và bạn có được không. Nhưng tôi muốn nói rằng nếu bạn muốn có những cái nhìn nhất quán về các mục, bạn sẽ cần phải bọc mỗi lần đọc và cập nhật một mục trong một khóa.
Oded

12
Tôi nghĩ đây không phải là những gì bác sĩ nói. Sự không nhất quán liên quan đến những gì mà chế độ xem chứa, nếu chế độ xem chỉ là giá trị thì nó hoàn toàn nhất quán. Miễn là bạn nhận được giá trị của một khóa, giá trị của khóa trong từ điển có thể thay đổi. Điều này không nhất quán như giá trị DateTime.Now.
George Mavritsakis

4

Cách tốt nhất để tìm ra điều này là kiểm tra tài liệu MSDN.

Đối với ConcurrentDictionary, trang này là http://msdn.microsoft.com/en-us/library/dd287191.aspx

Trong phần an toàn luồng, có ghi "Tất cả các thành viên công khai và được bảo vệ của ConcurrentDictionary (Của TKey, TValue) đều an toàn cho luồng và có thể được sử dụng đồng thời từ nhiều luồng."

Vì vậy, từ quan điểm đồng thời, bạn vẫn ổn.


2

Vâng, bạn đã đúng.

Điều đó và khả năng liệt kê từ điển trên một luồng trong khi thay đổi nó trên một luồng khác là phương tiện tồn tại duy nhất của lớp đó.


9
Điều tôi muốn thêm là đây là thông tin hữu ích về cách thức và thời điểm sử dụng ConcurrentDictionary.
alex.b

1

Nó phụ thuộc, trong trường hợp của tôi, tôi thích sử dụng phương pháp này hơn.

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

Xem Thư viện MSDN để biết chi tiết sử dụng phương pháp.

Sử dụng mẫu:

results.AddOrUpdate(
  Id,
  id => new DbResult() {
     Id = id,
     Value = row.Value,
     Rank = 1
  },
  (id, v) =>
  {
     v.Rank++;
     return v;
  });

2
FYI: "Khi bạn cung cấp phương thức nhà máy giá trị (cho phương thức GetOrAdd và AddOrUpdate), nó thực sự có thể chạy và kết quả của nó bị loại bỏ sau đó (vì một số luồng khác đã thắng cuộc đua)." Thông tin thêm tại đây: arbel.net/2013/02/03/…
keremispirli

Vâng, bạn nói đúng, như đã lưu ý trong phần nhận xét "Nếu bạn gọi AddOrUpdate đồng thời trên các chuỗi khác nhau, addValueFactory có thể được gọi nhiều lần, nhưng cặp khóa / giá trị của nó có thể không được thêm vào từ điển cho mỗi lần gọi." Vì vậy, bạn cần chắc chắn rằng bạn không tạo ra nhiều đối tượng liên tục.
Onur

Và nếu bạn cần cập nhật nội dung, không thay đổi hoàn toàn đối tượng được lưu trữ, chẳng hạn như thay đổi thuộc tính của đối tượng đã thêm trước đó, thì phương pháp này hữu ích, nếu không, bạn cần sử dụng khóa hoặc các phương pháp đồng bộ hóa khác.
Onur

1

Chỉ cần lưu ý: Không biện minh cho việc sử dụng đối tượng ConcurrentDicitionary với một vòng lặp tuyến tính, làm cho nó không được sử dụng đầy đủ. Giải pháp thay thế tốt nhất là làm theo các khuyến nghị của Tài liệu Microsoft, như được đề cập bởi Oded bằng cách sử dụng Song song, theo ví dụ dưới đây:

Parallel.For(0, 4, i => 
{
   myDic.TryAdd(i, 0);
});
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.