मेमोरी कैशे कैसे साफ़ करें?


100

मैंने MemoryCache क्लास का उपयोग करके कैश बनाया है। मैं इसमें कुछ आइटम जोड़ता हूं, लेकिन जब मुझे कैश को फिर से लोड करने की आवश्यकता होती है, तो मैं इसे पहले साफ़ करना चाहता हूं। ऐसा करने का सबसे तेज तरीका क्या है? क्या मुझे सभी वस्तुओं के माध्यम से लूप करना चाहिए और उन्हें एक बार में हटा देना चाहिए या बेहतर तरीका है?


1
.NET कोर के लिए इस उत्तर की जाँच करें
मकाला

जवाबों:


61

Dispose मौजूदा MemoryCache और एक नया MemoryCache ऑब्जेक्ट बनाएँ।


3
मैंने शुरुआत में MemoryCache.Default का इस्तेमाल किया, जिससे मुझे कुछ दुःख हुआ। फिर भी, डिस्पोज़ सबसे अच्छा समाधान है जो मुझे मिल सकता है। धन्यवाद।
LaustN

11
@LaustN क्या आप MemoryCache.Default की वजह से हुए "दुःख" पर विस्तार से बता सकते हैं? मैं वर्तमान में MemoryCache.Default का उपयोग कर रहा हूं ... MSDN के MemoryCache दस्तावेज़ीकरण से मुझे आश्चर्य होता है कि क्या डिस्पोज़ और रीक्रिएट करने की अनुशंसा की जाती है: "जब तक आवश्यक हो, मेमोरीकैश इंस्टेंस न बनाएं। यदि आप क्लाइंट और वेब एप्लिकेशन में कैश इंस्टेंसेस बनाते हैं, तो मेमोरी कैश इंस्टेंसेस चाहिए। आवेदन जीवन चक्र में जल्दी बनाया जाए। ” क्या यह .Default पर लागू होता है? मैं यह नहीं कह रहा हूं कि डिस्पोज़ का उपयोग करना गलत है, मैं ईमानदारी से सिर्फ इस सब पर स्पष्टीकरण की तलाश कर रहा हूं।
एलोनयू वेबदेव

8
सोचा था कि यह उल्लेख के लायक है कि था Dispose करता है किसी भी आह्वान CacheEntryRemovedCallbackवर्तमान कैश्ड आइटम से जुड़ी।
माइक गुथरी

8
@ ईलोनू: निम्नलिखित स्टैक ओवरफ्लो उत्तर कुछ ऐसे दुःख बताते हैं जिनसे आप डिफ़ॉल्ट उदाहरण का निपटान कर सकते हैं: stackoverflow.com/a/8043556/216440 । उद्धरण के लिए: "कैश की स्थिति को इंगित करने के लिए सेट किया गया है कि कैश का निपटान किया गया है। कैशिंग की स्थिति को बदलने वाले सार्वजनिक कैशिंग तरीकों को कॉल करने का कोई भी प्रयास, जैसे कि कैश प्रविष्टियों को जोड़ने, हटाने या पुनर्प्राप्त करने के तरीके अप्रत्याशित हो सकते हैं। व्यवहार। उदाहरण के लिए, यदि आप कैश के निपटान के बाद सेट विधि को कॉल करते हैं, तो एक नो-ऑप त्रुटि उत्पन्न होती है। "
साइमन टेवेसी

56

गणना के साथ समस्या

MemoryCache.GetEnumerator () खंड टिप्पणियां चेतावनी देते हैं: "। एक संसाधन प्रधान और अवरुद्ध आपरेशन है एक MemoryCache उदाहरण के लिए एक प्रगणक प्राप्त कर रहा है इसलिए, प्रगणक उत्पादन अनुप्रयोगों में नहीं किया जाना चाहिए।"

यहाँ क्यों , GetEnumerator () कार्यान्वयन के छद्मकोड में समझाया गया है:

Create a new Dictionary object (let's call it AllCache)
For Each per-processor segment in the cache (one Dictionary object per processor)
{
    Lock the segment/Dictionary (using lock construct)
    Iterate through the segment/Dictionary and add each name/value pair one-by-one
       to the AllCache Dictionary (using references to the original MemoryCacheKey
       and MemoryCacheEntry objects)
}
Create and return an enumerator on the AllCache Dictionary

चूंकि कार्यान्वयन कई शब्दकोश वस्तुओं में कैश को विभाजित करता है, इसलिए इसे एक एन्यूमरेटर को वापस करने के लिए एक संग्रह में सब कुछ एक साथ लाना होगा। GetEnumerator के लिए प्रत्येक कॉल ऊपर विस्तृत पूर्ण प्रतिलिपि प्रक्रिया निष्पादित करता है। नए बनाए गए शब्दकोश में मूल आंतरिक कुंजी और मूल्य वस्तुओं के संदर्भ शामिल हैं, इसलिए आपके वास्तविक कैश्ड डेटा मानों को डुप्लिकेट नहीं किया गया है।

प्रलेखन में चेतावनी सही है। GetEnumerator () से बचें - उपरोक्त सभी उत्तर जिसमें LINQ क्वेरी का उपयोग किया गया है।

एक बेहतर और अधिक लचीला समाधान

यहां कैश को साफ़ करने का एक प्रभावी तरीका है जो मौजूदा परिवर्तन निगरानी बुनियादी ढांचे पर बस बनाता है। यह या तो पूरे कैश या केवल नामांकित उप-समूह को साफ़ करने के लिए लचीलापन प्रदान करता है और ऊपर चर्चा की गई समस्याओं में से कोई भी नहीं है।

// By Thomas F. Abraham (http://www.tfabraham.com)
namespace CacheTest
{
    using System;
    using System.Diagnostics;
    using System.Globalization;
    using System.Runtime.Caching;

    public class SignaledChangeEventArgs : EventArgs
    {
        public string Name { get; private set; }
        public SignaledChangeEventArgs(string name = null) { this.Name = name; }
    }

    /// <summary>
    /// Cache change monitor that allows an app to fire a change notification
    /// to all associated cache items.
    /// </summary>
    public class SignaledChangeMonitor : ChangeMonitor
    {
        // Shared across all SignaledChangeMonitors in the AppDomain
        private static event EventHandler<SignaledChangeEventArgs> Signaled;

        private string _name;
        private string _uniqueId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);

        public override string UniqueId
        {
            get { return _uniqueId; }
        }

        public SignaledChangeMonitor(string name = null)
        {
            _name = name;
            // Register instance with the shared event
            SignaledChangeMonitor.Signaled += OnSignalRaised;
            base.InitializationComplete();
        }

        public static void Signal(string name = null)
        {
            if (Signaled != null)
            {
                // Raise shared event to notify all subscribers
                Signaled(null, new SignaledChangeEventArgs(name));
            }
        }

        protected override void Dispose(bool disposing)
        {
            SignaledChangeMonitor.Signaled -= OnSignalRaised;
        }

        private void OnSignalRaised(object sender, SignaledChangeEventArgs e)
        {
            if (string.IsNullOrWhiteSpace(e.Name) || string.Compare(e.Name, _name, true) == 0)
            {
                Debug.WriteLine(
                    _uniqueId + " notifying cache of change.", "SignaledChangeMonitor");
                // Cache objects are obligated to remove entry upon change notification.
                base.OnChanged(null);
            }
        }
    }

    public static class CacheTester
    {
        public static void TestCache()
        {
            MemoryCache cache = MemoryCache.Default;

            // Add data to cache
            for (int idx = 0; idx < 50; idx++)
            {
                cache.Add("Key" + idx.ToString(), "Value" + idx.ToString(), GetPolicy(idx));
            }

            // Flush cached items associated with "NamedData" change monitors
            SignaledChangeMonitor.Signal("NamedData");

            // Flush all cached items
            SignaledChangeMonitor.Signal();
        }

        private static CacheItemPolicy GetPolicy(int idx)
        {
            string name = (idx % 2 == 0) ? null : "NamedData";

            CacheItemPolicy cip = new CacheItemPolicy();
            cip.AbsoluteExpiration = System.DateTimeOffset.UtcNow.AddHours(1);
            cip.ChangeMonitors.Add(new SignaledChangeMonitor(name));
            return cip;
        }
    }
}

8
लापता क्षेत्र की कार्यक्षमता के लिए कार्यान्वयन की तरह लगता है।
Jowen

बहुत अच्छा। मैं जंजीर Memorycache मॉनिटर और guids का उपयोग करके कुछ को लागू करने की कोशिश कर रहा हूं, लेकिन यह थोड़ा बदसूरत होने लगा था क्योंकि मैंने कार्यक्षमता को कसने की कोशिश की थी।
चाओ

7
मैं इस पैटर्न को सामान्य उपयोग के लिए अनुशंसित नहीं करूंगा। 1. इसकी धीमी, कार्यान्वयन की कोई गलती नहीं है, लेकिन निपटान विधि बेहद धीमी है। 2. यदि आपके निष्कासन के साथ कैश से आइटम निकाल रहे हैं, तो परिवर्तन मॉनिटर अभी भी कहा जाता है। 3. मेरी मशीन CPU के सभी को निगल रही थी, और जब मैं प्रदर्शन परीक्षण चला रहा था, तब कैश से 30k आइटम को साफ़ करने के लिए वास्तव में लंबा समय ले रहा था। 5+ मिनट प्रतीक्षा करने के कुछ समय बाद मैंने सिर्फ परीक्षणों को मार दिया।
आरोन एम।

1
@PascalMathys दुर्भाग्य से, इससे बेहतर समाधान नहीं है। मैंने इसका उपयोग करना समाप्त कर दिया, नुकसान के बावजूद, क्योंकि यह अभी भी गणना का उपयोग करने से बेहतर समाधान है।
आरोन एम

9
@AaronM क्या यह समाधान अभी भी कैश के निपटान और एक नए को त्वरित करने से बेहतर है?
रोबसिक्लोस

35

से http://connect.microsoft.com/VisualStudio/feedback/details/723620/memorycache-class-needs-a-clear-method

वर्कअराउंड है:

List<string> cacheKeys = MemoryCache.Default.Select(kvp => kvp.Key).ToList();
foreach (string cacheKey in cacheKeys)
{
    MemoryCache.Default.Remove(cacheKey);
}

33
से प्रलेखन : एक MemoryCache उदाहरण के लिए एक प्रगणक प्राप्त कर रहा है एक संसाधन प्रधान और अवरुद्ध ऑपरेशन है। इसलिए, एन्यूमरेटर का उपयोग उत्पादन अनुप्रयोगों में नहीं किया जाना चाहिए।
ट्रूविल

3
@emberdude यह वास्तव में एक एन्यूमरेटर को पुनः प्राप्त करने के समान है - आप क्या Select()करता है कार्यान्वयन के बारे में बात करते हैं ?
रोबसिक्लोस

1
व्यक्तिगत रूप से, मैं अपने यूनिट टेस्ट [TestInitialize] फ़ंक्शन में प्रत्येक यूनिट टेस्ट के लिए मेमोरी कैश को खाली करने के लिए उपयोग कर रहा हूं। अन्यथा 2 कार्यों के बीच प्रदर्शन की तुलना करने की कोशिश करते समय कैश अनपेक्षित परिणाम देने वाले यूनिट परीक्षणों में बना रहता है।
जैकब मॉरिसन

6
@JacobMorrison यकीनन, इकाई परीक्षण "उत्पादन अनुप्रयोग" नहीं हैं :)
Mels

1
@Mels यकीनन, यूनिट परीक्षणों को "उत्पादन अनुप्रयोग" के समान मानकों पर लिखा जाना चाहिए! :)
एथेन

21
var cacheItems = cache.ToList();

foreach (KeyValuePair<String, Object> a in cacheItems)
{
    cache.Remove(a.Key);
}

3
इसमें @ टोनी की प्रतिक्रिया के समान जोखिम है; कृपया मेरी टिप्पणी उसी के तहत देखें।
ट्रूविल

@TrueWill @Tony कौन या कौन था?
एलेक्स एंगस

2
@AlexAngas - उन्होंने अपना नाम बदलकर मैग्रीट कर लिया होगा। यह भी देखें stackoverflow.com/questions/4183270/…
TrueWill

10

यदि प्रदर्शन कोई समस्या नहीं है, तो यह अच्छा एक-लाइनर चाल करेगा:

cache.ToList().ForEach(a => cache.Remove(a.Key));

7

ऐसा लगता है कि एक ट्रिम विधि है।

तो सभी सामग्री को साफ़ करने के लिए जो आप अभी करेंगे

cache.Trim(100)

EDIT: कुछ और खुदाई करने के बाद, ऐसा लगता है कि ट्रिम में देखना आपके समय के लायक नहीं है

https://connect.microsoft.com/VisualStudio/feedback/details/831755/memorycache-trim-method-doesnt-evict-100-of-the-items

मैं एक System.Runtime.Caching.MemoryCache कैसे साफ़ करूँ


3

आप भी कुछ ऐसा कर सकते हैं:


Dim _Qry = (From n In CacheObject.AsParallel()
           Select n).ToList()
For Each i In _Qry
    CacheObject.Remove(i.Key)
Next

3

इस पार दौड़ा, और इसके आधार पर, थोड़ा और अधिक प्रभावी, समानांतर स्पष्ट विधि लिखी:

    public void ClearAll()
    {
        var allKeys = _cache.Select(o => o.Key);
        Parallel.ForEach(allKeys, key => _cache.Remove(key));
    }

1
क्या आपने इसे देखने के लिए परीक्षण किया कि क्या यह तेज (या धीमा) है?
पॉल जॉर्ज

1

मैं केवल कैश को साफ़ करने में रुचि रखता था और इसे एक विकल्प के रूप में पाया, जब c # GlobalCachingProvider का उपयोग कर रहा था

                var cache = GlobalCachingProvider.Instance.GetAllItems();
                if (dbOperation.SuccessLoadingAllCacheToDB(cache))
                {
                    cache.Clear();
                }

0

मैग्रीट उत्तर का थोड़ा उन्नत संस्करण।

var cacheKeys = MemoryCache.Default.Where(kvp.Value is MyType).Select(kvp => kvp.Key).ToList();
foreach (string cacheKey in cacheKeys)
{
    MemoryCache.Default.Remove(cacheKey);
}

0

आप MemoryCache.Default कैश को डिस्पोज़ कर सकते हैं और फिर निजी फ़ील्ड सिंगलटन को शून्य में सेट कर सकते हैं, जिससे कि यह MemoryCache.Default को फिर से बना सके।

       var field = typeof(MemoryCache).GetField("s_defaultCache",
            BindingFlags.Static |
            BindingFlags.NonPublic);
        field.SetValue(null, null);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.