2013-11-23 10 views
6

मैं एक ऐप तैयार कर रहा हूं जिसके लिए कुछ प्रकार की कैशिंग की आवश्यकता है, और चूंकि मेरे मॉडल और व्यूमोडेल पोर्टेबल क्लास लाइब्रेरी में रहते हैं, इसलिए मैं वहां कुछ कैशिंग भी चाहता हूं ... लेकिन पीसीएल सीमित है, और मुझे लगता है कि कोई भी नहीं ढूंढ रहा ।पोर्टेबल क्लास लाइब्रेरी के लिए मेमोरी कैश में कोई है?

मैं सिस्टम का उपयोग करना चाहता हूं। रनटाइम। कैशिंग लेकिन पीसीएल में शामिल नहीं है - क्या कोई अन्य विकल्प है?

उत्तर

7

मैं खुद को ऐसे विकल्प की तलाश में हूं; मैं जल्द ही अपना खुद का कार्यान्वयन शुरू कर दूंगा, और इसे पोस्ट करूंगा। तब तक, यहां कुछ विचार दिए गए हैं जिन्हें आप आजमा सकते हैं।

रनटाइम। कैश अगर मुझे सही याद है तो सही समय पर आधारित कैश को अमान्य कर सकते हैं, स्लाइडिंग समय और कुंजी/फाइलों की निगरानी कर सकते हैं।

पहले आंकड़ा बाहर जो एक क्रियान्वित करना चाहिए

इस लिंक पर एक नज़र डालें (मैं निरपेक्ष और फिसलने हालांकि मैं महंगे होगा रपट विश्वास की जरूरत है)। alternative-to-concurrentdictionary-for-portable-class-library

मेरा विचार है कि वर्ग का विस्तार इतने पर प्रत्येक कैश आइटम जोड़ें/निकालें, हम स्टोर/कैश कुंजी आइटम फिसलने के लिए समाप्त करने के लिए समय के साथ एक शब्दकोश वस्तु में निकाल दें (हम पढ़ने पर यह समाप्ति समय अपडेट होता है,)

फिर हमारे पास एक मुख्य टाइमर है जो इस शब्दकोश को हर बार जांचता है और समय के आधार पर समाप्त हो जाता है।

यदि आप भी चाहते हैं, तो आप एक और शब्दकोश ट्रैकिंग कुंजी निर्भरताओं को ट्रैक कर सकते हैं, इसलिए कुंजी समाप्ति पर आप इस पर निर्भर किसी अन्य कैश की अवधि समाप्त कर सकते हैं।

उम्मीद है कि यह किसी भी तरह से मदद करता है।

--- अद्यतन

मैं .. चारों ओर अपने ही कार्यान्वयन लिखने के लिए ... यहाँ तुम जाओ पाने में कामयाब रहे

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Reactive.Linq; 
using System.Threading; 

namespace RanaInside.CacheProvider 
{ 
internal class CacheProvider : ICacheProvider 
{ 
    private IDictionary<object, CacheItem> _cache = new Dictionary<object, CacheItem>(); 
    private IDictionary<object, SliderDetails> _slidingTime = new Dictionary<object, SliderDetails>(); 

    private const int _monitorWaitDefault = 1000; 
    private const int _monitorWaitToUpdateSliding = 500; 

    /// <summary> 
    /// The sync object to make accessing the dictionary is thread safe. 
    /// </summary> 
    private readonly object _sync = new object(); 

    #region Implementation of Interface 

    public event EventHandler KeyRemoved; 

    /// <summary> 
    /// Add a value to the cache with a relative expiry time, e.g 10 minutes. 
    /// </summary> 
    /// <typeparam name="TKey">The type of the key.</typeparam> 
    /// <typeparam name="TValue">The type of the value.</typeparam> 
    /// <param name="key">The key.</param> 
    /// <param name="value">The value.</param> 
    /// <param name="slidingExpiry">The sliding time when the key value pair should expire and be purged from the cache.</param> 
    /// <param name="priority">Normal priority will be purged on low memory warning.</param> 
    public void Add<TKey, TValue>(TKey key, TValue value, TimeSpan slidingExpiry, CacheItemPriority priority = CacheItemPriority.Normal) where TValue : class 
    { 
     Add(key, value, slidingExpiry, priority, true); 
    } 

    /// <summary> 
    /// Add a value to the cache with an absolute time, e.g. 01/01/2020. 
    /// </summary> 
    /// <typeparam name="TKey">The type of the key.</typeparam> 
    /// <typeparam name="TValue">The type of the value.</typeparam> 
    /// <param name="key">The key.</param> 
    /// <param name="value">The value.</param> 
    /// <param name="absoluteExpiry">The absolute date time when the cache should expire and be purged the value.</param> 
    /// <param name="priority">Normal priority will be purged on low memory warning.</param> 
    public void Add<TKey, TValue>(TKey key, TValue value, DateTime absoluteExpiry, CacheItemPriority priority = CacheItemPriority.Normal) where TValue : class 
    { 
     if (absoluteExpiry < DateTime.Now) 
     { 
      return; 
     } 

     var diff = absoluteExpiry - DateTime.Now; 
     Add(key, value, diff, priority, false); 
    } 

    /// <summary> 
    /// Gets a value from the cache for specified key. 
    /// </summary> 
    /// <typeparam name="TKey">The type of the key.</typeparam> 
    /// <typeparam name="TValue">The type of the value.</typeparam> 
    /// <param name="key">The key.</param> 
    /// <returns> 
    /// If the key exists in the cache then the value is returned, if the key does not exist then null is returned. 
    /// </returns> 
    public TValue Get<TKey, TValue>(TKey key) where TValue : class 
    { 
     try 
     { 
      var cacheItem = _cache[key]; 

      if (cacheItem.RelativeExpiry.HasValue) 
      { 
       if (Monitor.TryEnter(_sync, _monitorWaitToUpdateSliding)) 
       { 
        try 
        { 
         _slidingTime[key].Viewed(); 
        } 
        finally 
        { 
         Monitor.Exit(_sync); 
        } 
       } 
      } 

      return (TValue)cacheItem.Value; 
     } 
     catch (Exception) 
     { 
      return null; 
     } 
    } 

    /// <summary> 
    /// Remove a value from the cache for specified key. 
    /// </summary> 
    /// <typeparam name="TKey">The type of the key.</typeparam> 
    /// <param name="key">The key.</param> 
    public void Remove<TKey>(TKey key) 
    { 
     if (!Equals(key, null)) 
     { 
      _cache.Remove(key); 
      _slidingTime.Remove(key); 

      if (KeyRemoved != null) 
      { 
       KeyRemoved(key, new EventArgs()); 
      } 
     } 
    } 

    /// <summary> 
    /// Clears the contents of the cache. 
    /// </summary> 
    public void Clear() 
    { 
     if (!Monitor.TryEnter(_sync, _monitorWaitDefault)) 
     { 
      return; 
     } 

     try 
     { 
      _cache.Clear(); 
      _slidingTime.Clear(); 
     } 
     finally 
     { 
      Monitor.Exit(_sync); 
     } 
    } 

    /// <summary> 
    /// Gets an enumerator for keys of a specific type. 
    /// </summary> 
    /// <typeparam name="TKey">The type of the key.</typeparam> 
    /// <returns> 
    /// Returns an enumerator for keys of a specific type. 
    /// </returns> 
    public IEnumerable<TKey> Keys<TKey>() 
    { 
     if (!Monitor.TryEnter(_sync, _monitorWaitDefault)) 
     { 
      return Enumerable.Empty<TKey>(); 
     } 

     try 
     { 
      return _cache.Keys.Where(k => k.GetType() == typeof(TKey)).Cast<TKey>().ToList(); 
     } 
     finally 
     { 
      Monitor.Exit(_sync); 
     } 
    } 

    /// <summary> 
    /// Gets an enumerator for all the keys 
    /// </summary> 
    /// <returns> 
    /// Returns an enumerator for all the keys. 
    /// </returns> 
    public IEnumerable<object> Keys() 
    { 
     if (!Monitor.TryEnter(_sync, _monitorWaitDefault)) 
     { 
      return Enumerable.Empty<object>(); 
     } 

     try 
     { 
      return _cache.Keys.ToList(); 
     } 
     finally 
     { 
      Monitor.Exit(_sync); 
     } 
    } 

    /// <summary> 
    /// Gets the total count of items in cache 
    /// </summary> 
    /// <returns> 
    /// -1 if failed 
    /// </returns> 
    public int TotalItems() 
    { 
     if (!Monitor.TryEnter(_sync, _monitorWaitDefault)) 
     { 
      return -1; 
     } 

     try 
     { 
      return _cache.Keys.Count; 
     } 
     finally 
     { 
      Monitor.Exit(_sync); 
     } 
    } 

    /// <summary> 
    /// Purges all cache item with normal priorities. 
    /// </summary> 
    /// <returns> 
    /// Number of items removed (-1 if failed) 
    /// </returns> 
    public int PurgeNormalPriorities() 
    { 
     if (Monitor.TryEnter(_sync, _monitorWaitDefault)) 
     { 
      try 
      { 
       var keysToRemove = (from cacheItem in _cache where cacheItem.Value.Priority == CacheItemPriority.Normal select cacheItem.Key).ToList(); 

       return keysToRemove.Count(key => _cache.Remove(key)); 
      } 
      finally 
      { 
       Monitor.Exit(_sync); 
      } 
     } 

     return -1; 
    } 

    #endregion 


    #region Private class helper 

    private void Add<TKey, TValue>(TKey key, TValue value, TimeSpan timeSpan, CacheItemPriority priority, bool isSliding) where TValue : class 
    { 
     if (!Monitor.TryEnter(_sync, _monitorWaitDefault)) 
     { 
      return; 
     } 

     try 
     { 
      // add to cache 
      _cache.Add(key, new CacheItem(value, priority, ((isSliding) ? timeSpan : (TimeSpan?)null))); 

      // keep sliding track 
      if (isSliding) 
      { 
       _slidingTime.Add(key, new SliderDetails(timeSpan)); 
      } 

      StartObserving(key, timeSpan); 
     } 
     finally 
     { 
      Monitor.Exit(_sync); 
     } 
    } 

    private void StartObserving<TKey>(TKey key, TimeSpan timeSpan) 
    { 
     Observable.Timer(timeSpan) 
      .Finally(() => 
      { 
       // on finished 
       GC.Collect(); 
       GC.WaitForPendingFinalizers(); 
      }) 
      // on next 
      .Subscribe(x => TryPurgeItem(key), 
      exception => 
      { 
       // on error: Purge Failed with exception.Message 
      }); 
    } 

    private void TryPurgeItem<TKey>(TKey key) 
    { 
     if (_slidingTime.ContainsKey(key)) 
     { 
      TimeSpan tryAfter; 
      if (!_slidingTime[key].CanExpire(out tryAfter)) 
      { 
       // restart observing 
       StartObserving(key, tryAfter); 
       return; 
      } 
     } 

     Remove(key); 
    } 

    private class CacheItem 
    { 
     public CacheItem() { } 

     public CacheItem(object value, CacheItemPriority priority, TimeSpan? relativeExpiry = null) 
     { 
      Value = value; 
      Priority = priority; 
      RelativeExpiry = relativeExpiry; 
     } 

     public object Value { get; set; } 

     public CacheItemPriority Priority { get; set; } 

     public TimeSpan? RelativeExpiry { get; set; } 
    } 


    private class SliderDetails 
    { 
     public SliderDetails(TimeSpan relativeExpiry) 
     { 
      RelativeExpiry = relativeExpiry; 
      Viewed(); 
     } 

     private TimeSpan RelativeExpiry { get; set; } 

     private DateTime ExpireAt { get; set; } 

     public bool CanExpire(out TimeSpan tryAfter) 
     { 
      tryAfter = (ExpireAt - DateTime.Now); 
      return (0 > tryAfter.Ticks); 
     } 

     public void Viewed() 
     { 
      ExpireAt = DateTime.Now.Add(RelativeExpiry); 
      var z = ExpireAt; 
     } 
    } 

    #endregion 

} 
} 

नवीनतम अद्यतन के लिए, कृपया

पर अपने ब्लॉग का दौरा http://ranahossain.blogspot.co.uk/2014/01/cache-provider-for-portable-class.html

0

हमारे पास एक ही समस्या थी और हमने अपनी आवश्यकताओं के लिए एक थ्रेड-सुरक्षित डेटा कैश बनाया। यह मोबाइल उपकरणों (पढ़ने और लिखने की समान मात्रा) के लिए अनुकूलित है, इसलिए हमने ReadWriterLockSlim या अन्य विकल्पों के बजाय सरल लॉकिंग का उपयोग किया।

विचार ईवेंट, समाप्ति, टैग और बाद में लॉकिंग जैसी अधिक कार्यक्षमता जोड़ना है। वर्तमान में यह केवल सहायक क्षेत्र है।

इससे हमारे प्रकाश स्तंभ फ्रेमवर्क का हिस्सा है और GitHub में पाया जा सकता:

https://github.com/Turneo/LightHouse/blob/master/Code/Core/Core/Code/Caching/DataCache.cs

0

एक बहुत अच्छा विकल्प (लेकिन लगातार कैश के लिए) Akavache है।

Akavache एक अतुल्यकालिक, लगातार (अर्थात डिस्क के लिए लिखता है) कुंजी-मान की दुकान सी #, sqlite3 के आधार पर में डेस्कटॉप और मोबाइल अनुप्रयोगों के लेखन के लिए बनाई गई है। अकावाचे महत्वपूर्ण डेटा (यानी उपयोगकर्ता सेटिंग्स) को संग्रहित करने के साथ-साथ कैश किए गए स्थानीय डेटा को समाप्त करने के लिए बहुत अच्छा है।

उदाहरण प्रलेखन से स्निपेट:

using System.Reactive.Linq; // IMPORTANT - this makes await work! 

// Make sure you set the application name before doing any inserts or gets 
BlobCache.ApplicationName = "AkavacheExperiment"; 

var myToaster = new Toaster(); 
await BlobCache.UserAccount.InsertObject("toaster", myToaster); 

// 
// ...later, in another part of town... 
// 

// Using async/await 
var toaster = await BlobCache.UserAccount.GetObject<Toaster>("toaster"); 

// or without async/await 
Toaster toaster; 

BlobCache.UserAccount.GetObject<Toaster>("toaster") 
    .Subscribe(x => toaster = x, ex => Console.WriteLine("No Key!")); 

दुर्भाग्य से अगर, मेरी तरह, आप पर डेस्कटॉप .NET4 लक्षित करने के लिए मजबूर किया जाता है, तो आप भाग्य से बाहर हैं। लेकिन आधुनिक अनुप्रयोगों के लिए मैं निश्चित रूप से इसके साथ जाऊंगा।

संपादित करें: अब मैं देखता हूं कि आपने केवल इन-मेमोरी केवल चाचे के लिए कहा था। मुझे नहीं लगता कि अकावचे इसका समर्थन करता है। मैं इस जवाब को हटा नहीं रहा हूं, क्योंकि मुझे लगता है कि पीसीएल कैश के लिए लोग गुगल रहे हैं, फिर भी यह उपयोगी हो सकता है।

संबंधित मुद्दे