2009-07-15 57 views
19

Tôi có một số nơi triển khai một số loại bộ nhớ cache có thể hữu ích. Ví dụ: trong trường hợp thực hiện tra cứu tài nguyên dựa trên chuỗi tùy chỉnh, hãy tìm tên thuộc tính bằng cách sử dụng phản chiếu hoặc chỉ có một tên là PropertyChangedEventArgs cho mỗi tên thuộc tính.C#: Cách triển khai bộ nhớ cache thông minh

Một ví dụ đơn giản mới nhất:

public static class Cache 
{ 
    private static Dictionary<string, PropertyChangedEventArgs> cache; 
    static Cache() 
    { 
     cache = new Dictionary<string, PropertyChangedEventArgs>(); 
    } 
    public static PropertyChangedEventArgs GetPropertyChangedEventArgs(
     string propertyName) 
    { 
     if (cache.ContainsKey(propertyName)) 
      return cache[propertyName]; 

     return cache[propertyName] = new PropertyChangedEventArgs(propertyName); 
    } 
} 

Nhưng, sẽ làm việc này không? Ví dụ, nếu chúng ta có một tải toàn bộ các thuộc tính khác nhau, điều đó có nghĩa là chúng ta sẽ kết thúc với một bộ nhớ đệm khổng lồ đang ngồi ở đó không bao giờ bị thu gom rác hoặc bất cứ thứ gì. Tôi đang tưởng tượng nếu những gì được lưu trữ là những giá trị lớn hơn và nếu ứng dụng là một ứng dụng dài, điều này có thể kết thúc như một vấn đề ... hoặc bạn nghĩ sao? Bộ đệm tốt nên được triển khai như thế nào? Cái này có đủ tốt cho hầu hết các mục đích không? Bất kỳ ví dụ về một số triển khai bộ nhớ cache tốt đẹp mà không phải là quá khó hiểu hoặc cách quá phức tạp để thực hiện?

+12

"* Chỉ có hai điều cứng Khoa học Máy tính:. Huỷ bỏ hiệu lực bộ nhớ cache và điều đặt tên *" - Phil Karlton – JulianR

+1

Đây là không đáng một câu trả lời toàn bộ, nhưng việc thực hiện đặc biệt này sẽ thất bại một cách ngoạn mục trong môi trường đa luồng. Ở mức tối thiểu bạn cần một khóa xung quanh quyền truy cập vào 'cache' trong' GetPropertyChangedEventArgs() '. Chỉ cố gắng giúp đỡ bất kỳ ai đến cùng và sao chép-pastas này. – aaronburro

Trả lời

18

Bạn có thể gói từng mục trong bộ nhớ cache của mình trong một số WeakReference. Điều này sẽ cho phép GC khôi phục các mục nếu và khi được yêu cầu, tuy nhiên nó không cung cấp cho bạn bất kỳ kiểm soát chi tiết nào khi các mục sẽ biến mất khỏi bộ nhớ cache hoặc cho phép bạn triển khai các chính sách hết hạn rõ ràng, v.v.

(Ha Tôi chỉ nhận thấy rằng ví dụ được đưa ra trên MSDN page là một lớp bộ nhớ đệm đơn giản.)

+1

Mát mẻ! Chính xác thì WeakReference làm gì trong trường hợp này? – Svish

+1

Trang này có một lời giải thích tốt: http://msdn.microsoft.com/en-us/library/ms404247.aspx – LukeH

+4

Trong thực tế, tôi thấy rằng các.NET GC là rất hiệu quả/tích cực mà tài liệu tham khảo yếu không treo xung quanh lâu, có nghĩa là chúng chỉ thực sự phù hợp với dữ liệu ngắn ngủi và/hoặc không tốn kém để tạo lại. – LukeH

3

Đây là một cuộc tranh luận thú vị khi có, nhưng tùy thuộc ứng dụng của bạn, sau đây là một số lời khuyên:

Bạn nên xác định kích thước tối đa của bộ nhớ cache, phải làm gì với mục cũ nếu bộ nhớ cache của bạn là đầy đủ, có nhặt rác chiến lược, xác định thời gian để sống của đối tượng trong bộ nhớ cache, bộ nhớ cache của bạn có thể/phải được lưu giữ ở một nơi khác mà bộ nhớ, trong trường hợp kết thúc ứng dụng bất thường ...

+1

Chiến lược nhặt rác là gì? – Svish

+4

Thuật toán nhặt rác có trách nhiệm xóa các mục khỏi bộ nhớ cache sang tài nguyên lưu trữ bộ nhớ cache miễn phí. –

+0

Ah, ok. Điều đó có ý nghĩa. – Svish

24

Đây là một vấn đề lớn, bạn cần phải xác định miền của vấn đề và áp dụng các kỹ thuật chính xác. Ví dụ, làm thế nào bạn sẽ mô tả sự hết hạn của các đối tượng? Họ có trở nên cũ trong một khoảng thời gian cố định không? Họ có trở thành cũ từ một sự kiện bên ngoài không? Tần suất này xảy ra như thế nào? Ngoài ra, bạn có bao nhiêu đối tượng? Cuối cùng, chi phí để tạo ra đối tượng là bao nhiêu?

Chiến lược đơn giản nhất là thực hiện ghi nhớ thẳng, như bạn đã nêu ở trên. Điều này giả định rằng các đối tượng không bao giờ hết hạn, và rằng không có quá nhiều để chạy bộ nhớ của bạn khô mà bạn nghĩ rằng chi phí để tạo ra các đối tượng này đảm bảo việc sử dụng bộ nhớ cache để bắt đầu.

Lớp tiếp theo có thể là giới hạn số lượng đối tượng và sử dụng chính sách hết hạn tiềm ẩn, chẳng hạn như LRU (ít được sử dụng gần đây nhất). Để làm điều này, bạn thường sẽ sử dụng một danh sách liên kết gấp đôi ngoài từ điển của bạn, và mỗi khi một đối tượng được truy cập nó sẽ được chuyển đến trước danh sách. Sau đó, nếu bạn cần thêm một đối tượng mới, nhưng nó vượt quá giới hạn tổng số đối tượng của bạn, bạn sẽ xóa khỏi mặt sau của danh sách.

Tiếp theo, bạn có thể cần phải thực thi hết hạn rõ ràng, dựa trên thời gian hoặc một số kích thích bên ngoài. Điều này sẽ yêu cầu bạn phải có một số loại sự kiện hết hạn có thể được gọi.

Như bạn có thể thấy có rất nhiều thiết kế trong bộ nhớ đệm, vì vậy bạn cần hiểu tên miền và kỹ sư của bạn một cách thích hợp. Bạn đã không cung cấp đủ chi tiết để tôi thảo luận chi tiết cụ thể, tôi cảm thấy.

P.S. Vui lòng xem xét sử dụng Generics khi định nghĩa lớp của bạn để có thể lưu trữ nhiều loại đối tượng, do đó cho phép sử dụng lại mã bộ nhớ đệm của bạn.

+2

+1 để đề cập đến nhiều yếu tố và đề xuất các giải pháp cơ bản. –

+0

Tôi loại ra spesifics chỉ vì tôi hy vọng tôi sẽ nhận được lời khuyên chung hơn về những gì để suy nghĩ về vv Vì vậy, cảm ơn bạn cho rằng :) Ngày sử dụng Generics, bạn có nghĩa là để trao đổi ra Cache với Cache và trao đổi ra tất cả các PropertyChangedEventArgs với T là tốt? Hoặc một cái gì đó thông minh hơn? Không phải tất cả các đối tượng khác đều có ý nghĩa để xác định bằng một chuỗi mà tôi nghĩ ... – Svish

+1

Chỉ là các generics cơ bản có, bạn có thể muốn sử dụng cùng mẫu với Từ điển và cho phép người dùng bộ nhớ cache của bạn xác định loại K và V. –

3

Đây là vấn đề phổ biến có nhiều giải pháp tùy thuộc vào nhu cầu ứng dụng của bạn. Rất phổ biến là Microsoft đã phát hành toàn bộ thư viện để giải quyết nó. Bạn nên kiểm tra Microsoft Velocity trước khi cuộn bộ nhớ cache của riêng bạn. http://msdn.microsoft.com/en-us/data/cc655792.aspx Hy vọng trợ giúp này.

+0

+1 - Thư viện này có vẻ như nó có nguồn gốc của nó trong Khối ứng dụng Caching từ thư viện doanh nghiệp. –

+0

Giờ đây được gọi là "Dịch vụ lưu bộ nhớ AppFabric". Nó thiếu hai từ khóa ở đây: tính di động và miễn phí. Tại sao Microsoft không thể phát hành một cái gì đó như một phần tiêu chuẩn của .NET? –

1

Bạn có thể sử dụng WeakReference nhưng nếu đối tượng của bạn không lớn hơn không vì WeakReference sẽ lấy nhiều bộ nhớ hơn đối tượng không phải là kỹ thuật tốt. Ngoài ra, nếu đối tượng là một thời gian ngắn sử dụng, nơi nó sẽ không bao giờ làm cho nó đến thế hệ 1 từ thế hệ 0 trên GC, không có nhiều nhu cầu cho WeakReference nhưng giao diện IDisposable trên đối tượng sẽ có với việc phát hành trên SuppressFinalize.

Nếu bạn muốn kiểm soát tuổi thọ, bạn cần một bộ đếm thời gian để cập nhật datetime/timespan một lần nữa mong muốnExpirationTime trên đối tượng trong bộ nhớ cache của bạn.

Điều quan trọng là nếu đối tượng lớn thì hãy chọn tham chiếu WeakReference khác sử dụng tham chiếu mạnh. Ngoài ra, bạn có thể đặt dung lượng trên từ điển và tạo hàng đợi để yêu cầu các đối tượng bổ sung trong thùng tuần tự của bạn tuần tự hóa đối tượng và tải nó khi có chỗ trong từ điển, sau đó xóa nó khỏi thư mục tạm thời.

9

Dường như .NET 4.0 hiện hỗ trợ System.Runtime.Caching để lưu vào bộ nhớ cache nhiều loại sự vật. Bạn nên nhìn vào đó đầu tiên, thay vì tái phát minh ra bánh xe. Thông tin chi tiết:

http://msdn.microsoft.com/en-us/library/system.runtime.caching%28VS.100%29.aspx

+4

Trừ khi nó sử dụng String làm khóa và Object cho giá trị của bản đồ! Người đàn ông những gì một sự thất vọng, làm thế nào họ có thể thực hiện một API chung chung như một bộ nhớ cache và không sử dụng generics cho các loại khóa/đối tượng? – marq

+0

Vâng, tôi có thể hiểu bằng cách sử dụng String cho một khóa. Tôi không biết về bất kỳ đối tượng băm nào mà ít nhất cũng chuyển đổi khóa đó thành một thứ dựa trên String. Và không phải Object chỉ là một container chung? –

+0

@BrendanByrd Mọi đối tượng đều có phương thức mã băm. – Casey

Các vấn đề liên quan