2012-01-25 46 views
11

Tôi cần thêm chức năng bộ nhớ cache và tìm thấy một lớp sáng bóng mới có tên là MemoryCache. Tuy nhiên, tôi tìm thấy MemoryCache một chút tê liệt vì nó là (tôi đang cần chức năng vùng). Trong số những thứ khác tôi cần phải thêm một cái gì đó như ClearAll (khu vực). Các tác giả đã nỗ lực rất lớn để giữ cho lớp này không có hỗ trợ vùng, mã như:MemoryCache có hỗ trợ vùng không?

bay theo hầu hết mọi phương pháp. Tôi không thấy cách dễ dàng để ghi đè hành vi này. Cách duy nhất để thêm hỗ trợ vùng mà tôi có thể nghĩ đến là thêm một lớp mới như là một trình bao bọc của MemoryCache thay vì sau đó là một lớp kế thừa từ MemoryCache. Sau đó, trong lớp mới này tạo một từ điển và cho phép mỗi phương thức "vùng đệm" gọi. Âm thanh khó chịu và sai, nhưng cuối cùng ...

Bạn có biết cách nào tốt hơn để thêm vùng vào MemoryCache không?

Trả lời

5

Bạn có thể tạo nhiều hơn một cá thể MemoryCache, một cho mỗi phân đoạn dữ liệu của bạn.

http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.aspx:

bạn có thể tạo nhiều trường hợp của các lớp MemoryCache để sử dụng trong cùng một ứng dụng và trong cùng dụ AppDomain

+0

nơi tốt nhất để khởi tạo tất cả các phiên bản MemoryCache mới này? Có một nhà cung cấp MemoryCache, nơi bạn có thể quản lý tất cả các trường hợp này? –

+0

@ HenleyChiu Tôi không nghĩ có gì trong thư viện cơ sở. Chỉ cần sử dụng các phương tiện chuẩn để chia sẻ trạng thái, ví dụ: một tĩnh, trên toàn cầu có thể nhìn thấy [ConcurrentDictionary ] (http://msdn.microsoft.com/en-us/library/dd287191.aspx) –

+2

Sử dụng nhiều phiên bản của 'MemoryCache' có thể làm giảm hiệu quả của bộ nhớ đệm trong một số hoàn cảnh. Xem: http://stackoverflow.com/questions/8463962/using-multiple-instances-of-memorycache – Nathan

9

Tôi biết đó là một thời gian dài kể từ khi bạn hỏi này câu hỏi, vì vậy đây không thực sự là câu trả lời cho bạn, mà là một sự bổ sung cho độc giả trong tương lai.

Tôi cũng ngạc nhiên khi thấy rằng việc triển khai chuẩn của MemoryCache KHÔNG hỗ trợ các vùng. Nó sẽ dễ dàng được cung cấp ngay lập tức. Do đó, tôi đã quyết định đưa MemoryCache vào lớp đơn giản của riêng mình để cung cấp chức năng mà tôi thường cần.

Tôi đính kèm mã của mình ở đây để tiết kiệm thời gian cho những người khác có cùng nhu cầu!

/// <summary> 
/// ================================================================================================================= 
/// This is a static encapsulation of the Framework provided MemoryCache to make it easier to use. 
/// - Keys can be of any type, not just strings. 
/// - A typed Get method is provided for the common case where type of retrieved item actually is known. 
/// - Exists method is provided. 
/// - Except for the Set method with custom policy, some specific Set methods are also provided for convenience. 
/// - One SetAbsolute method with remove callback is provided as an example. 
/// The Set method can also be used for custom remove/update monitoring. 
/// - Domain (or "region") functionality missing in default MemoryCache is provided. 
/// This is very useful when adding items with identical keys but belonging to different domains. 
/// Example: "Customer" with Id=1, and "Product" with Id=1 
/// ================================================================================================================= 
/// </summary> 
public static class MyCache 
{ 
    private const string KeySeparator = "_"; 
    private const string DefaultDomain = "DefaultDomain"; 


    private static MemoryCache Cache 
    { 
     get { return MemoryCache.Default; } 
    } 

    // ----------------------------------------------------------------------------------------------------------------------------- 
    // The default instance of the MemoryCache is used. 
    // Memory usage can be configured in standard config file. 
    // ----------------------------------------------------------------------------------------------------------------------------- 
    // cacheMemoryLimitMegabytes: The amount of maximum memory size to be used. Specified in megabytes. 
    //        The default is zero, which indicates that the MemoryCache instance manages its own memory 
    //        based on the amount of memory that is installed on the computer. 
    // physicalMemoryPercentage: The percentage of physical memory that the cache can use. It is specified as an integer value from 1 to 100. 
    //        The default is zero, which indicates that the MemoryCache instance manages its own memory 
    //        based on the amount of memory that is installed on the computer. 
    // pollingInterval:    The time interval after which the cache implementation compares the current memory load with the 
    //        absolute and percentage-based memory limits that are set for the cache instance. 
    //        The default is two minutes. 
    // ----------------------------------------------------------------------------------------------------------------------------- 
    // <configuration> 
    // <system.runtime.caching> 
    //  <memoryCache> 
    //  <namedCaches> 
    //   <add name="default" cacheMemoryLimitMegabytes="0" physicalMemoryPercentage="0" pollingInterval="00:02:00" /> 
    //  </namedCaches> 
    //  </memoryCache> 
    // </system.runtime.caching> 
    // </configuration> 
    // ----------------------------------------------------------------------------------------------------------------------------- 



    /// <summary> 
    /// Store an object and let it stay in cache until manually removed. 
    /// </summary> 
    public static void SetPermanent(string key, object data, string domain = null) 
    { 
     CacheItemPolicy policy = new CacheItemPolicy { }; 
     Set(key, data, policy, domain); 
    } 

    /// <summary> 
    /// Store an object and let it stay in cache x minutes from write. 
    /// </summary> 
    public static void SetAbsolute(string key, object data, double minutes, string domain = null) 
    { 
     CacheItemPolicy policy = new CacheItemPolicy { AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(minutes) }; 
     Set(key, data, policy, domain); 
    } 

    /// <summary> 
    /// Store an object and let it stay in cache x minutes from write. 
    /// callback is a method to be triggered when item is removed 
    /// </summary> 
    public static void SetAbsolute(string key, object data, double minutes, CacheEntryRemovedCallback callback, string domain = null) 
    { 
     CacheItemPolicy policy = new CacheItemPolicy { AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(minutes), RemovedCallback = callback }; 
     Set(key, data, policy, domain); 
    } 

    /// <summary> 
    /// Store an object and let it stay in cache x minutes from last write or read. 
    /// </summary> 
    public static void SetSliding(object key, object data, double minutes, string domain = null) 
    { 
     CacheItemPolicy policy = new CacheItemPolicy { SlidingExpiration = TimeSpan.FromMinutes(minutes) }; 
     Set(key, data, policy, domain); 
    } 

    /// <summary> 
    /// Store an item and let it stay in cache according to specified policy. 
    /// </summary> 
    /// <param name="key">Key within specified domain</param> 
    /// <param name="data">Object to store</param> 
    /// <param name="policy">CacheItemPolicy</param> 
    /// <param name="domain">NULL will fallback to default domain</param> 
    public static void Set(object key, object data, CacheItemPolicy policy, string domain = null) 
    { 
     Cache.Add(CombinedKey(key, domain), data, policy); 
    } 




    /// <summary> 
    /// Get typed item from cache. 
    /// </summary> 
    /// <param name="key">Key within specified domain</param> 
    /// <param name="domain">NULL will fallback to default domain</param> 
    public static T Get<T>(object key, string domain = null) 
    { 
     return (T)Get(key, domain); 
    } 

    /// <summary> 
    /// Get item from cache. 
    /// </summary> 
    /// <param name="key">Key within specified domain</param> 
    /// <param name="domain">NULL will fallback to default domain</param> 
    public static object Get(object key, string domain = null) 
    { 
     return Cache.Get(CombinedKey(key, domain)); 
    } 

    /// <summary> 
    /// Check if item exists in cache. 
    /// </summary> 
    /// <param name="key">Key within specified domain</param> 
    /// <param name="domain">NULL will fallback to default domain</param> 
    public static bool Exists(object key, string domain = null) 
    { 
     return Cache[CombinedKey(key, domain)] != null; 
    } 

    /// <summary> 
    /// Remove item from cache. 
    /// </summary> 
    /// <param name="key">Key within specified domain</param> 
    /// <param name="domain">NULL will fallback to default domain</param> 
    public static void Remove(object key, string domain = null) 
    { 
     Cache.Remove(CombinedKey(key, domain)); 
    } 



    #region Support Methods 

    /// <summary> 
    /// Parse domain from combinedKey. 
    /// This method is exposed publicly because it can be useful in callback methods. 
    /// The key property of the callback argument will in our case be the combinedKey. 
    /// To be interpreted, it needs to be split into domain and key with these parse methods. 
    /// </summary> 
    public static string ParseDomain(string combinedKey) 
    { 
     return combinedKey.Substring(0, combinedKey.IndexOf(KeySeparator)); 
    } 

    /// <summary> 
    /// Parse key from combinedKey. 
    /// This method is exposed publicly because it can be useful in callback methods. 
    /// The key property of the callback argument will in our case be the combinedKey. 
    /// To be interpreted, it needs to be split into domain and key with these parse methods. 
    /// </summary> 
    public static string ParseKey(string combinedKey) 
    { 
     return combinedKey.Substring(combinedKey.IndexOf(KeySeparator) + KeySeparator.Length); 
    } 

    /// <summary> 
    /// Create a combined key from given values. 
    /// The combined key is used when storing and retrieving from the inner MemoryCache instance. 
    /// Example: Product_76 
    /// </summary> 
    /// <param name="key">Key within specified domain</param> 
    /// <param name="domain">NULL will fallback to default domain</param> 
    private static string CombinedKey(object key, string domain) 
    { 
     return string.Format("{0}{1}{2}", string.IsNullOrEmpty(domain) ? DefaultDomain : domain, KeySeparator, key); 
    } 

    #endregion 

} 
+1

Việc đếm qua MemoryCache không hiệu quả vì nó sẽ khóa toàn bộ bộ nhớ cache trong thời gian đó. Ngoài ra, Clear() của bạn là một tìm kiếm tuyến tính để trở nên tồi tệ hơn với số lượng các mục trong bộ nhớ cache tuyến tính. Đây là một giải pháp tốt hơn: http://stackoverflow.com/a/22388943/220230 – Piedone

+0

Cảm ơn bạn đã quan sát điều này. Trong ví dụ đơn giản nhất định, tôi đã loại bỏ phương thức Clear để tránh những người khác lạc lối. Đối với những người thực sự cần một cách để loại bỏ bằng tay theo vùng tôi tham khảo các liên kết nhất định. –

0

Một cách tiếp cận khác là triển khai trình bao bọc xung quanh MemoryCache thực hiện vùng bằng cách tạo tên khóa và vùng, ví dụ:

public interface ICache 
{ 
... 
    object Get(string key, string regionName = null); 
... 
} 

public class MyCache : ICache 
{ 
    private readonly MemoryCache cache 

    public MyCache(MemoryCache cache) 
    { 
     this.cache = cache. 
    } 
... 
    public object Get(string key, string regionName = null) 
    { 
     var regionKey = RegionKey(key, regionName); 

     return cache.Get(regionKey); 
    } 

    private string RegionKey(string key, string regionName) 
    { 
     // NB Implements region as a suffix, for prefix, swap order in the format 
     return string.IsNullOrEmpty(regionName) ? key : string.Format("{0}{1}{2}", key, "::", regionName); 
    } 
... 
} 

Nó không hoàn hảo nhưng nó hoạt động trong hầu hết các trường hợp sử dụng.

Tôi đã triển khai tính năng này và nó có sẵn dưới dạng gói NuGet: Meerkat.Caching