2010-12-17 1 views
8

tôi đã bắt đầu làm việc với một số mã NET 3.5 và thấy phương pháp mở rộng sau đây được sử dụng cho một bộ nhớ cache ::Đối với .NET 3.5, bạn sẽ tạo một bộ đệm an toàn hoặc thêm bộ nhớ cache như thế nào?

public static TValue GetOrAdd<TKey, TValue>(this Dictionary<TKey, TValue> @this, TKey key,Func<TKey,TValue> factory,bool useLocking) 
{ 

    TValue value; 
    if([email protected](key,out value)) 
    { 
     if (useLocking) 
     { 
      lock ((@this as ICollection).SyncRoot) 
      { 
       if ([email protected](key, out value)) 
       { 
        @this[key] = value = factory(key); 
       } 
      } 
     } 
     else 
     { 
      @this[key] = value = factory(key); 
     } 
    } 
    return value; 
} 

Bộ nhớ cache trong câu hỏi là keyed bởi phím chuỗi, và với useLocking = true. Nó luôn luôn được truy cập bằng phương pháp này (không có đi lạc TryGetValue). Cũng không có vấn đề gì trong việc sử dụng thuộc tính SyncRoot vì từ điển là riêng tư và không có nơi nào khác được sử dụng. Khóa kép nguy hiểm vì một từ điển không hỗ trợ đọc trong khi nó được ghi vào. Mặc dù về mặt kỹ thuật, chưa có vấn đề nào được báo cáo vì sản phẩm không được vận chuyển, tôi cảm thấy rằng cách tiếp cận này sẽ dẫn đến các điều kiện chủng tộc.

  1. Chuyển Dictionary<,> thành Hashtable. Chúng tôi sẽ mất an toàn loại nhưng chúng tôi sẽ có thể hỗ trợ mô hình đồng thời mà chúng tôi đang theo dõi, (1 nhà văn, nhiều người đọc).

  2. Xóa bên ngoài TryGetValue. Bằng cách đó mọi đọc, đòi hỏi phải có một khóa. Điều này có khả năng xấu cho hiệu suất, nhưng có được một khóa không được kiểm soát nên khá rẻ.

Cả hai đều khá crappy. Có ai có đề xuất tốt hơn không? Nếu đây là mã .NET 4, tôi chỉ chuyển nó thành ConcurrentDictionary, nhưng tôi không có tùy chọn đó.

+5

Yargh! Hoàn toàn không liên quan ... nhưng không viết mã bằng cách sử dụng @this. Bạn đang ở trong một phương pháp tĩnh; không cố gắng làm cho nó trông giống như một phương pháp thể hiện. –

+0

đây không phải là mã của tôi! Nếu đó là mã của tôi, tôi sẽ thêm xác thực đối số. –

Trả lời

0

Xóa TryGetValue. Tôi đặt cược bạn sẽ không thấy vấn đề đồng thời; Các màn hình CLR khá nhanh, và "không công bằng" để bạn không thấy các vấn đề trục trặc hoặc đảo ngược ưu tiên.

Nếu bạn thấy sự cố đồng thời, thì điều tốt nhất tiếp theo là ReaderWriterLockSlim. Thật không may, bạn sẽ muốn tạo một lớp mới cho rằng thay vì sử dụng một phương pháp mở rộng, bởi vì bạn sẽ cần một nơi để lưu trữ khóa.

Nếu bạn đi tuyến đường đó, hãy chắc chắn tránh xa việc nâng cấp từ đầu đọc sang ổ ghi của nhà văn.

0

Tôi nghĩ bạn cần khóa câu lệnh hoàn chỉnh (như bạn đã nêu).

Tuy nhiên, có một giải pháp gọn gàng trên web để chuẩn bị cho tương lai .NET 4 nâng cấp: Có lớp tùy chỉnh thay vì từ điển, giữ từ điển là biến thành viên riêng và bao gồm tất cả quyền truy cập vào từ điển trong chuỗi -bảo mật khóa an toàn. Mô tả chi tiết có thể được tìm thấy tại đây: http://www.grumpydev.com/2010/02/25/thread-safe-dictionarytkeytvalue/

2

Có, sự nghi ngờ của bạn là chính xác; có một điều kiện chủng tộc và tất cả các phương pháp, ngay cả TryGetValue cần phải ở trong khóa trong quá trình triển khai mà bạn đã trình bày.

Theo như hiệu suất, bạn có thể mong đợi ngày mà bạn có thể nâng cấp lên .NET4 bao gồm một tiếng la hét nhanh ConcurrentDictionary ra khỏi hộp. Cho đến lúc đó, bạn có thể xem phân tích James Michael Hare của thực hiện ở đây:

Những kết quả cho thấy với tôi rằng việc thực hiện tốt nhất cho .NET3.5 là Dictionary cộng ReadWriteLockSlim và cho biện pháp tốt, đây là một thực hiện đầy đủ:

Cập nhật:

Tôi đọc các bảng sai và có vẻ như Dictionary + lock rất ít nhanh hơn đối thủ nghiêm trọng duy nhất khác Dictionary + ReadWriteLockSlim.

+1

Hài hước, những kết quả đó đề nghị * tôi * rằng một 'Từ điển' với khóa mutex là cách thực hiện tốt nhất. Đó là nhanh hơn trên bảng so với việc thực hiện rw-lock. – Gabe

+0

Rất tiếc, tôi đã quét quá nhanh và đọc bảng đó dưới dạng hoạt động trên một đơn vị thời gian, thay vì thời gian cho mỗi đơn vị hoạt động. –

+1

Bài viết với toàn bộ Thread Safe Safe thực hiện đã biến mất, nhưng sau một chút đào tôi nghĩ rằng tôi đã tìm thấy [thực hiện chính nó] (http://www.codekeep.net/snippets/b2afc386-13cc-4297- a327-dbf52dd7498a.aspx) (chỉ mã, không bình luận/giải thích). – Dusty

1

Đề xuất của tôi là tải xuống Reactive Extensions for .NET (Rx), bao gồm backports của bộ sưu tập trong không gian tên System.Collections.Concurrent (bao gồm ConcurrentDictionary<TKey, TValue>) cho .NET 3.5.

+2

Không còn ở đó kể từ ngày 19 tháng 10 năm 2012. – rickythefox