System.Runtime.Caching.MemoryCache vs HttpRuntime.Cache - gibt es Unterschiede?

84

Ich frage mich, ob es Unterschiede zwischen MemoryCacheund HttpRuntime.Cachegibt. Welches wird in ASP.NET MVC-Projekten bevorzugt?

Soweit ich weiß, sind beide threadsicher. Die API ist auf den ersten Blick mehr oder weniger gleich. Gibt es also einen Unterschied, wann welche verwendet werden soll?

Giedrius
quelle

Antworten:

80

HttpRuntime.Cachebekommt das Cachefür die aktuelle anwendung.

Die MemoryCacheKlasse ähnelt der ASP.NET- CacheKlasse.

Die MemoryCacheKlasse verfügt über viele Eigenschaften und Methoden für den Zugriff auf den Cache, die Ihnen bekannt sind, wenn Sie die ASP.NET- CacheKlasse verwendet haben.

Der Hauptunterschied zwischen HttpRuntime.Cacheund MemoryCachebesteht darin, dass letzteres geändert wurde, damit es von .NET Framework-Anwendungen verwendet werden kann, die keine ASP.NET-Anwendungen sind.

Für zusätzliche Lektüre:

Update:

Laut dem Feedback der Benutzer funktioniert der Blog von Jon Davis manchmal nicht. Daher habe ich den gesamten Artikel als Bild eingefügt. Bitte sehen Sie das.

Hinweis: Wenn es nicht klar ist, klicken Sie einfach auf das Bild. Danach wird es in einem Browser geöffnet. Klicken Sie dann erneut darauf, um zu zoomen :)

Geben Sie hier die Bildbeschreibung ein

Sampath
quelle
Dieser Artikel von John Davis ist wirklich gut zu lesen - klare Vor- und Nachteile an einem Ort.
Giedrius
Absolut alles ist an einem Ort. Gut. Zusätzlich erwähnte Davis auch 4 verschiedene Caching-Methoden.
Sampath
2
@ Spikeh Es wird gut für mich geladen.
user247702
1
@Stijn Danke, wurde neulich nicht geladen, aber es ist jetzt zurück :)
Spikeh
1
@sampath es funktioniert jetzt. Gestern sah es so aus, als ob die Seite gehackt wurde. Danke für Ihre Hilfe!
Baga
24

Hier ist der Artikel von Jon Davis. Um die Lesbarkeit zu gewährleisten, schneide ich den mittlerweile veralteten EntLib-Abschnitt, das Intro sowie die Schlussfolgerung aus.


ASP.NET-Cache

ASP.NET oder die Assembly System.Web.dll verfügt über einen Caching-Mechanismus. Es war nie für die Verwendung außerhalb eines Webkontexts vorgesehen, kann jedoch außerhalb des Webkontexts verwendet werden und führt alle oben genannten Ablaufverhalten in einer Art Hashtabelle aus.

Nach dem Durchsuchen von Google scheint es, dass einige Leute, die die in .NET integrierte Caching-Funktionalität erörtert haben, in ihren Nicht-Web-Projekten auf die Verwendung des ASP.NET-Cache zurückgegriffen haben. Dies ist nicht mehr das am besten verfügbare und am meisten unterstützte integrierte Caching-System in .NET. .NET 4 verfügt über einen ObjectCache, auf den ich später noch eingehen werde. Microsoft hat immer darauf bestanden, dass der ASP.NET-Cache nicht für die Verwendung außerhalb des Webs vorgesehen ist. Viele Menschen stecken jedoch immer noch in .NET 2.0 und .NET 3.5 fest und benötigen etwas, mit dem sie arbeiten können. Dies funktioniert bei vielen Menschen, obwohl MSDN klar sagt:

Hinweis: Die Cache-Klasse ist nicht für die Verwendung außerhalb von ASP.NET-Anwendungen vorgesehen. Es wurde für die Verwendung in ASP.NET entwickelt und getestet, um das Caching für Webanwendungen bereitzustellen. In anderen Arten von Anwendungen, z. B. Konsolenanwendungen oder Windows Forms-Anwendungen, funktioniert das ASP.NET-Caching möglicherweise nicht ordnungsgemäß.

Die Klasse für den ASP.NET-Cache ist System.Web.Caching.Cache in System.Web.dll. Sie können ein Cache-Objekt jedoch nicht einfach neu erstellen. Sie müssen es von System.Web.HttpRuntime.Cache erwerben.

Cache cache = System.Web.HttpRuntime.Cache;

Die Arbeit mit dem ASP.NET-Cache ist hier auf MSDN dokumentiert .

Vorteile:

  1. Es ist eingebaut .
  2. Trotz der .NET 1.0-Syntax ist die Verwendung recht einfach .
  3. Wenn es in einem Webkontext verwendet wird, ist es gut getestet . Außerhalb von Webkontexten ist es laut Google-Suche nicht allgemein bekannt, dass es Probleme verursacht, obwohl Microsoft davon abrät, solange Sie .NET 2.0 oder höher verwenden.
  4. Sie können über einen Delegaten benachrichtigt werden, wenn ein Element entfernt wird. Dies ist erforderlich, wenn Sie es am Leben erhalten müssen und die Priorität des Elements nicht im Voraus festlegen konnten.
  5. Einzelne Elemente haben die Flexibilität einer der Ablauf- und Entfernungsmethoden (a), (b) oder (c) in der Liste der Entfernungsmethoden oben in diesem Artikel. Sie können das Ablaufverhalten auch mit dem Vorhandensein einer physischen Datei verknüpfen.

Nachteile:

  1. Es ist nicht nur statisch, es gibt nur eine . Sie können keinen eigenen Typ mit einer eigenen statischen Instanz eines Caches erstellen. Sie können nur einen Bucket für Ihre gesamte App haben. Sie können den Bucket mit Ihren eigenen Wrappern umwickeln, die beispielsweise Präfixe in die Schlüssel einfügen, und diese Präfixe entfernen, wenn Sie die Schlüssel / Wert-Paare wieder herausziehen. Aber es gibt immer noch nur einen Eimer. Alles ist zusammengewürfelt. Dies kann ein echtes Ärgernis sein, wenn Sie beispielsweise einen Dienst haben, der drei oder vier verschiedene Arten von Daten separat zwischenspeichern muss. Dies sollte kein großes Problem für pathetisch einfache Projekte sein. Wenn ein Projekt jedoch aufgrund seiner Anforderungen einen erheblichen Komplexitätsgrad aufweist, reicht der ASP.NET-Cache normalerweise nicht aus.
  2. Gegenstände können wohl oder übel verschwinden. Viele Leute sind sich dessen nicht bewusst - ich war es nicht, bis ich mein Wissen über diese Cache-Implementierung aktualisiert habe. Standardmäßig ist der ASP.NET-Cache so konzipiert, dass Elemente zerstört werden, wenn er sich "anfühlt". Genauer gesagt, siehe (c) in meiner Definition einer Cache-Tabelle oben in diesem Artikel. Wenn ein anderer Thread im selben Prozess an etwas völlig anderem arbeitet und Elemente mit hoher Priorität in den Cache kopiert, werden, sobald .NET entscheidet, dass er Speicher benötigt, einige Elemente im Cache entsprechend zerstört ihre Prioritäten, niedrigere Prioritäten zuerst. Alle hier dokumentierten Beispiele zum Hinzufügen von Cache-Elementen verwenden die Standardpriorität anstelle des Prioritätswerts NotRemovable, der verhindert, dass sie zum Löschen des Speichers entfernt werden, sie jedoch gemäß der Ablaufrichtlinie entfernt.
  3. Der Schlüssel muss eine Zeichenfolge sein. Wenn Sie beispielsweise Datensätze zwischenspeichern, bei denen die Datensätze auf einer langen oder einer ganzen Zahl verschlüsselt sind, müssen Sie den Schlüssel zuerst in eine Zeichenfolge konvertieren.
  4. Die Syntax ist veraltet . Die .NET 1.0-Syntax ist noch hässlicher als ArrayList oder Hashtable. Hier gibt es keine Generika, keine IDictionary <> -Schnittstelle. Es gibt keine Contains () -Methode, keine Keys-Auflistung und keine Standardereignisse. Es gibt nur eine Get () -Methode und einen Indexer, der dasselbe wie Get () ausführt und null zurückgibt, wenn keine Übereinstimmung vorliegt, sowie Add (), Insert () (redundant?), Remove () und GetEnumerator (). .
  5. Ignoriert das DRY-Prinzip zum Einrichten Ihres Standard- Ablauf- / Entfernungsverhaltens, damit Sie es vergessen können. Sie müssen dem Cache explizit mitteilen, wie das hinzugefügte Element ablaufen oder jedes Mal entfernt werden soll, wenn Sie ein Element hinzufügen.
  6. Keine Möglichkeit, auf die Caching-Details eines zwischengespeicherten Elements zuzugreifen , z. B. auf den Zeitstempel, zu dem es hinzugefügt wurde. Die Kapselung ging hier etwas über Bord, was es schwierig machte, den Cache zu verwenden, wenn Sie im Code versuchen zu bestimmen, ob ein zwischengespeichertes Element gegen einen anderen Caching-Mechanismus (dh Sitzungssammlung) ungültig gemacht werden soll oder nicht.
  7. Entfernungsereignisse werden nicht als Ereignisse angezeigt und müssen zum Zeitpunkt des Hinzufügens nachverfolgt werden.
  8. Und wenn ich es nicht genug gesagt habe, empfiehlt Microsoft ausdrücklich, es außerhalb des Webs abzulehnen. Und wenn Sie mit .NET 1.1 verflucht sind , sollten Sie es außerhalb des Webs überhaupt nicht mit Sicherheit für Stabilität verwenden. Machen Sie sich also keine Sorgen.

ObjectCache / MemoryCache von .NET 4.0

Microsoft hat schließlich eine abstrakte ObjectCache-Klasse in der neuesten Version von .NET Framework und eine MemoryCache-Implementierung implementiert, die ObjectCache für speicherinterne Zwecke in einer Nicht-Web-Umgebung erbt und implementiert.

System.Runtime.Caching.ObjectCache befindet sich in der Assembly System.Runtime.Caching.dll. Es ist eine abstrakte Klasse, die im Grunde dieselben .NET 1.0-Schnittstellen deklariert, die im ASP.NET-Cache gefunden werden. System.Runtime.Caching.MemoryCacheist die speicherinterne Implementierung von ObjectCache und ähnelt mit einigen Änderungen dem ASP.NET-Cache.

Um ein Element mit einem verschiebbaren Ablauf hinzuzufügen, sieht Ihr Code ungefähr so ​​aus:

var config = new NameValueCollection();  
var cache = new MemoryCache("myMemCache", config);  
cache.Add(new CacheItem("a", "b"),  
    new CacheItemPolicy  
    {  
        Priority = CacheItemPriority.NotRemovable,  
        SlidingExpiration=TimeSpan.FromMinutes(30)  
    }); 

Vorteile:

  1. Es ist integriert und wird jetzt von Microsoft außerhalb des Webs unterstützt und empfohlen.
  2. Im Gegensatz zum ASP.NET-Cache können Sie eine MemoryCache-Objektinstanz instanziieren.

    Hinweis: Es muss nicht statisch sein, sollte es aber sein - das ist die Empfehlung von Microsoft (siehe gelbe Achtung) .

  3. Im Vergleich zur Benutzeroberfläche des ASP.NET-Cache wurden einige geringfügige Verbesserungen vorgenommen, z. B. die Möglichkeit, Entfernungsereignisse zu abonnieren, ohne dass diese beim Hinzufügen der Elemente unbedingt vorhanden sein müssen. Das redundante Insert () wurde entfernt. Elemente können mit einem CacheItem hinzugefügt werden Objekt mit einem Initialisierer, der die Caching-Strategie definiert, und Contains () wurde hinzugefügt.

Nachteile:

  1. Verstärkt DRY immer noch nicht vollständig. Aufgrund meiner geringen Erfahrung können Sie den gleitenden Ablauf TimeSpan immer noch nicht einmal einstellen und vergessen. Und ehrlich gesagt, obwohl die Richtlinie im obigen Beispiel zum Hinzufügen von Elementen besser lesbar ist, erfordert sie eine schreckliche Ausführlichkeit.
  2. Es ist immer noch nicht generisch verschlüsselt. Es erfordert eine Zeichenfolge als Schlüssel. Sie können also nicht so lange oder int speichern, wenn Sie Datensätze zwischenspeichern, es sei denn, Sie konvertieren in eine Zeichenfolge.

DIY: Bauen Sie sich selbst

Es ist eigentlich ziemlich einfach, ein Caching-Wörterbuch zu erstellen, das einen expliziten oder gleitenden Ablauf ausführt. (Es wird viel schwieriger, wenn Elemente zum Löschen des Speichers automatisch entfernt werden sollen.) Hier ist alles, was Sie tun müssen:

  1. Erstellen Sie eine Wertcontainerklasse mit dem Namen Expiring oder Expiring, die einen Wert vom Typ T, eine TimeStamp-Eigenschaft vom Typ DateTime zum Speichern, wenn der Wert zum Cache hinzugefügt wurde, und einen TimeSpan enthält, der angibt, wie weit der Zeitstempel davon entfernt ist Der Artikel sollte verfallen. Für einen expliziten Ablauf können Sie einfach einen Eigenschaftssetzer verfügbar machen, der die Zeitspanne bei einem vom Zeitstempel abgezogenen Datum festlegt.
  2. Erstellen Sie eine Klasse, nennen wir sie ExpiringItemsDictionary, die IDictionary implementiert. Ich ziehe es vor, es zu einer generischen Klasse zu machen, die vom Verbraucher definiert wird.
  3. Fügen Sie in der in # 2 erstellten Klasse ein Dictionary> als Eigenschaft hinzu und nennen Sie es InnerDictionary.
  4. Die Implementierung von IDictionary in der in # 2 erstellten Klasse sollte das InnerDictionary zum Speichern zwischengespeicherter Elemente verwenden. Durch die Kapselung werden die Details der Caching-Methode über Instanzen des in Nr. 1 oben erstellten Typs ausgeblendet.
  5. Stellen Sie sicher, dass der Indexer (this []), ContainsKey () usw. sorgfältig abgelaufene Elemente löscht und die abgelaufenen Elemente entfernt, bevor Sie einen Wert zurückgeben. Geben Sie in getters null zurück, wenn das Element entfernt wurde.
  6. Verwenden Sie Thread-Sperren für alle Getter, Setter, ContainsKey () und insbesondere beim Löschen der abgelaufenen Elemente.
  7. Löse ein Ereignis aus, wenn ein Gegenstand aufgrund eines Ablaufs entfernt wird.
  8. Fügen Sie eine System.Threading.Timer-Instanz hinzu und manipulieren Sie sie während der Initialisierung, um abgelaufene Elemente alle 15 Sekunden automatisch zu entfernen. Dies ist das gleiche Verhalten wie beim ASP.NET-Cache.
  9. Möglicherweise möchten Sie eine AddOrUpdate () - Routine hinzufügen, die den gleitenden Ablauf verschiebt, indem Sie den Zeitstempel auf dem Container des Elements (ablaufende Instanz) ersetzen, falls dieser bereits vorhanden ist.

Microsoft muss seine ursprünglichen Designs unterstützen, da seine Benutzerbasis eine Abhängigkeit von ihnen aufgebaut hat. Dies bedeutet jedoch nicht, dass es sich um gute Designs handelt.

Vorteile:

  1. Sie haben die vollständige Kontrolle über die Implementierung.
  2. Kann DRY verstärken, indem Standard-Caching-Verhaltensweisen eingerichtet und dann einfach Schlüssel / Wert-Paare eingefügt werden, ohne die Caching-Details jedes Mal zu deklarieren, wenn Sie ein Element hinzufügen.
  3. Kann nämlich moderne Schnittstellen implementieren IDictionary<K,T>. Dies erleichtert die Verwendung erheblich, da die Benutzeroberfläche als Wörterbuchschnittstelle vorhersehbarer ist und für Helfer und Erweiterungsmethoden, die mit IDictionary <> arbeiten, zugänglicher ist.
  4. Caching-Details können nicht gekapselt werden , z. B. indem Sie Ihr InnerDictionary über eine öffentliche schreibgeschützte Eigenschaft verfügbar machen. So können Sie explizite Komponententests für Ihre Caching-Strategie schreiben und Ihre grundlegende Caching-Implementierung um zusätzliche Caching-Strategien erweitern, die darauf aufbauen.
  5. Obwohl dies nicht unbedingt eine vertraute Benutzeroberfläche für diejenigen ist, die sich bereits mit der .NET 1.0-Syntax des ASP.NET-Caches oder des Caching-Anwendungsblocks vertraut gemacht haben, können Sie die Benutzeroberfläche so definieren , wie sie aussehen soll.
  6. Kann einen beliebigen Typ für Schlüssel verwenden. Dies ist ein Grund, warum Generika erstellt wurden. Nicht alles sollte mit einer Zeichenfolge verschlüsselt werden.

Nachteile:

  1. Wird nicht von Microsoft erfunden oder unterstützt , daher wird es nicht die gleiche Qualitätssicherung geben.
  2. Unter der Annahme, dass nur die oben beschriebenen Anweisungen implementiert sind, werden Elemente zum Löschen des Speichers nicht vorrangig gelöscht (was ohnehin eine Eckfunktion eines Cache ist). KAUFEN Sie RAM, wo Sie den Cache verwenden würden , RAM ist billig).

Unter allen vier dieser Optionen ist dies meine Präferenz. Ich habe diese grundlegende Caching-Lösung implementiert. Bisher scheint es perfekt zu funktionieren, es sind keine Fehler bekannt (bitte kontaktieren Sie mich mit Kommentaren unten oder bei jon-at-jondavis, falls vorhanden !!), und ich beabsichtige, es in all meinen kleineren Nebenprojekten zu verwenden, die benötigt werden Grundlegendes Caching. Hier ist es:

Github-Link: https://github.com/kroimon/ExpiringItemDictionary

Alter Link: ExpiringItemDictionary.zip

Erwähnenswert: AppFabric, NoSQL et al

Beachten Sie, dass der Titel dieses Blog-Artikels "Simple Caching" und nicht "Heavy-Duty Caching" angibt. Wenn Sie sich mit Schwerlast beschäftigen möchten, sollten Sie sich dedizierte, skalierbare Lösungen ansehen.

DeepSpace101
quelle
3

MemoryCache ist das, was es verspricht, ein im Speicher gespeicherter Cache

HttpRuntime.Cache (siehe http://msdn.microsoft.com/en-us/library/system.web.httpruntime.cache(v=vs.100).aspx und http://msdn.microsoft.com/en- us / library / system.web.caching.cache.aspx ) bleibt bei dem, was Sie in Ihrer Anwendung konfigurieren.

Siehe zum Beispiel "ASP.NET 4.0: Benutzerdefinierte Ausgabe-Cache-Anbieter schreiben" http://weblogs.asp.net/gunnarpeipman/archive/2009/11/19/asp-net-4-0-writing-custom-output-cache -providers.aspx

Christian Westman
quelle
1
Hm, ich bin mir nicht sicher, ob der zweite Link nicht irreführend ist, da über OutputCache und die Implementierung von OutputCacheProvider gesprochen wird.
Giedrius
Hm, ich kann nicht finden, wo es heißt, dass Sie System.Web.Caching.Cache mit unterschiedlicher Konfiguration beibehalten können
Giedrius
2

MemoryCache.Default kann auch als "Brücke" dienen, wenn Sie eine klassische ASP.NET MVC-App auf ASP.NET Core migrieren, da in Core keine "System.Web.Caching" und "HttpRuntime" vorhanden sind.

Ich habe auch einen kleinen Benchmark geschrieben, um ein boolElement 20000 Mal zu speichern (und einen anderen Benchmark, um es abzurufen), und MemoryCache scheint zweimal langsamer zu sein (27 ms gegenüber 13 ms - das ist insgesamt für alle 20.000 Iterationen), aber beide sind superschnell und dies kann wahrscheinlich ignoriert werden.

Alex
quelle