web-dev-qa-db-fra.com

System.Runtime.Caching.MemoryCache vs HttpRuntime.Cache - existe-t-il des différences?

Je me demande s’il existe des différences entre MemoryCache et HttpRuntime.Cache, lequel est préféré dans les projets ASP.NET MVC?

Autant que je sache, les deux sont thread-safe, l'API est à première vue plus ou moins la même chose, y a-t-il une différence quand utiliser lequel?

83
Giedrius

HttpRuntime.Cache obtient le Cache pour l'application en cours.

La classe MemoryCache est similaire à la classe ASP.NET Cache.

La classe MemoryCache possède de nombreuses propriétés et méthodes d'accès au cache qui vous seront familières si vous avez utilisé la classe ASP.NET Cache.

La principale différence entre HttpRuntime.Cache and MemoryCache est que ce dernier a été modifié pour le rendre utilisable par les applications .NET Framework qui ne sont pas des applications ASP.NET.

Pour des lectures supplémentaires:

Mise à jour:

Selon les commentaires des utilisateurs, parfois, le blog de Jon davis ne fonctionne pas. C'est pourquoi j'ai mis l'ensemble de l'article sous forme d'image.Veuillez vous en assurer.

Remarque: Si ce n'est pas clair, cliquez simplement sur l'image.Après cela, il s'ouvrira sur un navigateur.Puis cliquez à nouveau dessus pour zoomer :)

enter image description here

78
Sampath

Voici l'article de Jon Davis. Pour préserver la lisibilité, je supprime la section EntLib désormais obsolète, l'intro ainsi que la conclusion.


Cache ASP.NET

ASP.NET, ou l’assemblée System.Web.dll, dispose d’un mécanisme de mise en cache. Il n'a jamais été conçu pour être utilisé en dehors d'un contexte Web, mais il peut être utilisé en dehors du Web et exécute tous les comportements d'expiration ci-dessus dans une sorte de table de hachage.

Après avoir parcouru Google, il semble que bon nombre de personnes ayant discuté de la fonctionnalité de mise en cache intégrée à .NET ont eu recours à la mémoire cache ASP.NET dans leurs projets non Web. Ce n'est plus le système de mise en cache intégré le plus disponible, le plus pris en charge dans .NET; .NET 4 a un ObjectCache dans lequel je reviendrai plus tard. Microsoft a toujours insisté sur le fait que le cache ASP.NET n'était pas destiné à être utilisé en dehors du Web. Mais beaucoup de gens sont toujours bloqués dans .NET 2.0 et .NET 3.5 et ont besoin de quelque chose avec qui travailler, et cela arrive à travailler pour beaucoup de gens, même si MSDN dit clairement:

Remarque: La classe Cache n'est pas destinée à être utilisée en dehors des applications ASP.NET. Il a été conçu et testé pour être utilisé dans ASP.NET afin de permettre la mise en cache des applications Web. Dans d'autres types d'applications, telles que les applications console ou les applications Windows Forms, la mise en cache ASP.NET peut ne pas fonctionner correctement.

La classe pour le cache ASP.NET est System.Web.Caching.Cache dans System.Web.dll. Cependant, vous ne pouvez pas simplement créer un objet Cache. Vous devez l’acquérir auprès de System.Web.HttpRuntime.Cache.

Cache cache = System.Web.HttpRuntime.Cache;

Travailler avec le cache ASP.NET est documenté sur MSDN here .

Avantages:

  1. C'est intégré .
  2. Malgré la syntaxe .NET 1.0, il est relativement simple à utiliser .
  3. Lorsqu'il est utilisé dans un contexte Web, il est bien testé . En dehors des contextes Web, selon les recherches Google, il n’est généralement pas connu que des problèmes se produisent, malgré les recommandations de Microsoft, dans la mesure où vous utilisez .NET 2.0 ou une version ultérieure.
  4. Vous pouvez être averti par l'intermédiaire d'un délégué lorsqu'un élément est supprimé, ce qui est nécessaire si vous devez le conserver en vie et que vous ne pouvez pas définir la priorité de l'élément dans avance.
  5. Les éléments individuels ont la flexibilité de n’importe laquelle des méthodes (a), (b) ou (c) d’expiration et de suppression de la liste des méthodes de suppression à le haut de cet article. Vous pouvez également associer un comportement d'expiration à la présence d'un fichier physique.

Les inconvénients:

  1. Non seulement il est statique, il n'y en a qu'un . Vous ne pouvez pas créer votre propre type avec sa propre instance statique d'un cache. Vous ne pouvez avoir qu'un seul seau pour l'ensemble de votre application, point final. Vous pouvez envelopper le seau avec vos propres wrappers qui font des choses comme pré-injecter des préfixes dans les clés et supprimer ces préfixes lorsque vous retirez les paires clé/valeur. Mais il n'y a toujours qu'un seul seau. Tout est regroupé. Cela peut être une véritable gêne si, par exemple, vous avez un service qui doit mettre en cache trois ou quatre types de données différents séparément. Cela ne devrait pas être un gros problème pour des projets aussi simples que pathétiques. Toutefois, si un projet présente un degré de complexité important en raison de ses exigences, le cache ASP.NET ne suffit généralement pas.
  2. Les objets peuvent disparaître, bon gré mal gré . Beaucoup de gens ne sont pas au courant de cela - je ne le savais pas, jusqu'à ce que je mette à jour mes connaissances sur cette implémentation de cache. Par défaut, le cache ASP.NET est conçu pour détruire les éléments quand il en a l’impression. Plus spécifiquement, voir (c) dans ma définition d’une table de cache en haut de cet article. Si un autre thread du même processus travaille sur quelque chose de complètement différent et qu'il vide des éléments de haute priorité dans le cache, dès que .NET décide qu'il a besoin de mémoire, il commence à détruire certains éléments dans le cache en fonction de leurs priorités, les priorités les plus faibles en premier. Tous les exemples décrits ici pour l'ajout d'éléments de cache utilisent la priorité par défaut plutôt que la valeur de priorité NotRemovable, qui l'empêche d'être supprimée à des fins de nettoyage de la mémoire, mais le supprimera tout de même conformément à la stratégie d'expiration. Peppering CacheItemPriority.NotRemovable dans les invocations de cache peut être fastidieux, sinon un wrapper est nécessaire.
  3. La clé doit être une chaîne. Si, par exemple, vous mettez en cache des enregistrements de données dans lesquels les enregistrements sont saisis sur un entier ou un entier, vous devez convertir la clé d'une chaîne en premier.
  4. La syntaxe est obsolète . C’est la syntaxe .NET 1.0, encore plus laide que ArrayList ou Hashtable. Il n'y a pas de générique ici, pas d'interface IDictionary <>. Il n'a pas de méthode Contains (), pas de collection Keys, pas d'événements standard; il ne dispose que d'une méthode Get () et d'un indexeur faisant la même chose que Get (), renvoyant la valeur null s'il n'y a pas de correspondance, plus Add (), Insert () (redondant?), Remove () et GetEnumerator () .
  5. Ignore le principe DRY de la configuration de vos comportements d'expiration/suppression par défaut afin que vous puissiez les oublier. Vous devez indiquer explicitement au cache comment vous souhaitez que l'élément que vous ajoutez expire ou soit supprimé chaque fois que vous ajoutez un élément.
  6. Aucun moyen d'accéder aux détails de la mise en cache d'un élément mis en cache, tel que l'horodatage de son ajout. L’encapsulation a été un peu exagérée ici, rendant difficile l’utilisation du cache lorsque vous tentez de déterminer dans un code si un élément mis en cache doit être invalidé par rapport à un autre mécanisme de mise en cache (c’est-à-dire une collection de session).
  7. Les événements de suppression ne sont pas exposés en tant qu'événements et doivent être suivis au moment de l'ajout.
  8. Et si je ne le dis pas assez, Microsoft le recommande explicitement en dehors du Web. Et si vous êtes maudit avec . NET 1.1, vous n’êtes pas censé l’utiliser avec une quelconque assurance de stabilité en dehors du Web, ne vous embêtez pas.

ObjectCache/MemoryCache de .NET 4.0

Microsoft a finalement mis en œuvre une classe ObjectCache abstraite dans la dernière version du .NET Framework et une implémentation MemoryCache qui hérite et implémente ObjectCache à des fins en mémoire dans un paramètre non Web.

System.Runtime.Caching.ObjectCache est dans l'assembly System.Runtime.Caching.dll. Il s'agit d'une classe abstraite qui déclare essentiellement les mêmes interfaces de style .NET 1.0 que celles trouvées dans le cache ASP.NET. System.Runtime.Caching.MemoryCache Est l'implémentation en mémoire d'ObjectCache et est très similaire au cache ASP.NET, avec quelques modifications.

Pour ajouter un élément avec une expiration glissante, votre code devrait ressembler à ceci:

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)  
    }); 

Avantages:

  1. Il est intégré et est maintenant pris en charge et recommandé par Microsoft en dehors du Web.
  2. Contrairement au cache ASP.NET, vous pouvez instancier une instance d'objet MemoryCache.

    Remarque: il n’est pas nécessaire que ce soit statique, mais cela devrait être — c’est-à-dire recommandation de Microsoft (voir Mise en garde jaune) .

  3. Quelques légères améliorations ont été apportées par rapport à l'interface du cache ASP.NET, telles que la possibilité de s'abonner à des événements de suppression sans être nécessairement présent lors de l'ajout des éléments, l'insertion redondante de Insert (), les éléments peuvent être ajoutés avec un CacheItem. objet avec un initialiseur qui définit la stratégie de mise en cache, et Contains () a été ajouté.

Les inconvénients:

  1. Ne renforce toujours pas complètement DRY. De par ma petite expérience, vous ne pouvez toujours pas régler l’expiration de glissement TimeSpan une fois et l’oublier. Et franchement, bien que la politique décrite ci-dessus soit plus lisible, elle nécessite une verbosité épouvantable.
  2. Ce n'est toujours pas générique. il nécessite une chaîne comme clé. Donc, vous ne pouvez pas stocker aussi longtemps ou int si vous mettez en cache des enregistrements de données, à moins que vous ne convertissiez en chaîne.

DIY: Construis toi-même

En fait, il est très simple de créer un dictionnaire de mise en cache qui effectue une expiration explicite ou glissante. (Cela devient beaucoup plus difficile si vous souhaitez que les éléments soient automatiquement supprimés à des fins d’effacement de la mémoire.) Voici tout ce que vous devez faire:

  1. Créez une classe de conteneur de valeur appelée quelque chose comme Expiration ou Expirable, qui contiendrait une valeur de type T, une propriété TimeStamp de type DateTime à stocker lorsque la valeur était ajoutée au cache et un TimeSpan indiquant le décalage entre l'horodatage et la valeur. l'élément devrait expirer. Pour une expiration explicite, vous pouvez simplement exposer un configurateur de propriété qui définit TimeSpan en fonction d'une date soustraite par l'horodatage.
  2. Créez une classe, appelons-la ExpirableItemsDictionary, qui implémente IDictionary. Je préfère en faire une classe générique définie par le consommateur.
  3. Dans la classe créée dans # 2, ajoutez un dictionnaire> en tant que propriété et appelez-le InnerDictionary.
  4. L'implémentation si IDictionary dans la classe créée dans # 2 doit utiliser InnerDictionary pour stocker les éléments mis en cache. L'encapsulation masquerait les détails de la méthode de mise en cache via des instances du type créé dans # 1 ci-dessus.
  5. Assurez-vous que l'indexeur (this []), ContainsKey (), etc., veille à bien effacer les éléments expirés et à les supprimer avant de renvoyer une valeur. Renvoie null dans les accesseurs si l'élément a été supprimé.
  6. Utilisez des verrous de fil sur tous les accesseurs, les régleurs, ContainsKey (), et en particulier lorsque vous supprimez les éléments arrivés à expiration.
  7. Déclenche un événement chaque fois qu'un élément est supprimé en raison de son expiration.
  8. Ajoutez une instance System.Threading.Timer et configurez-la lors de l'initialisation pour supprimer automatiquement les éléments arrivés à expiration toutes les 15 secondes. C'est le même comportement que le cache ASP.NET.
  9. Vous souhaiterez peut-être ajouter une routine AddOrUpdate () qui expulse l'expiration glissante en remplaçant l'horodatage sur le conteneur de l'élément (instance Expiring) s'il existe déjà.

Microsoft doit prendre en charge ses conceptions d'origine car sa base d'utilisateurs a créé une dépendance à leur égard, mais cela ne signifie pas pour autant qu'il s'agit de bonnes conceptions.

Avantages:

  1. Vous avez le contrôle complet de la mise en œuvre.
  2. Peut renforcer DRY en définissant des comportements de mise en cache par défaut, puis en supprimant simplement les paires clé/valeur sans déclarer les détails de la mise en cache chaque fois que vous ajoutez un élément.
  3. Peut implémenter des interfaces modernes , à savoir IDictionary<K,T>. Cela facilite grandement la consommation, car son interface est plus prévisible en tant qu'interface de dictionnaire, et le rend plus accessible aux aides et aux méthodes d'extension qui fonctionnent avec IDictionary <>.
  4. Les détails de la mise en cache peuvent être non encapsulés , par exemple en exposant votre InnerDictionary via une propriété publique en lecture seule, ce qui vous permet d'écrire des tests unitaires explicites par rapport à votre stratégie de mise en cache. ainsi que d'étendre votre implémentation de mise en cache de base avec des stratégies de mise en cache supplémentaires qui s'appuient sur celle-ci.
  5. Bien que ce ne soit pas nécessairement une interface familière pour ceux qui se sont déjà familiarisés avec la syntaxe de style .NET 1.0 du cache ASP.NET ou du bloc d’application de mise en cache, vous pouvez définir l’interface pour ressembler à ce que vous voulez.
  6. Peut utiliser n'importe quel type pour les clés. C'est l'une des raisons pour lesquelles des génériques ont été créés. Tout ne doit pas être saisi avec une chaîne.

Les inconvénients:

  1. N’est pas inventé ni approuvé par Microsoft , de sorte qu’il n’aura pas la même assurance qualité.
  2. En supposant que seules les instructions que je viens de décrire soient mises en œuvre, ne supprimez pas "bon gré mal gré" les éléments permettant d'effacer la mémoire en priorité (fonction utilitaire de cache d'une cache de toute façon .. BUY RAM utiliser le cache, RAM est bon marché).

Parmi ces quatre options, c'est ma préférence. J'ai mis en œuvre cette solution de mise en cache de base. Jusqu'à présent, il semble fonctionner parfaitement, il n'y a pas de bugs connus (s'il vous plaît contactez-moi avec les commentaires ci-dessous ou à jon-at-jondavis s'il y en a !!), et j'ai l'intention de l'utiliser dans tous mes petits projets secondaires qui en ont besoin mise en cache de base. C'est ici:

Lien Github: https://github.com/kroimon/ExpirableItemDictionary

Ancien lien: ExpirableItemDictionary.Zip

Digne de mention: AppFabric, NoSQL, Et Al

Notez que le titre de cet article de blog indique "Mise en cache simple", pas "Mise en cache robuste". Si vous souhaitez vous lancer dans le travail intensif, vous devez rechercher des solutions spécifiques et évolutives.

22
DeepSpace101

MemoryCache est ce qu'il est dit, un cache stocké dans mémoire

HttpRuntime.Cache (voir http://msdn.Microsoft.com/en-us/library/system.web.httpruntime.cache (v = vs.100) .aspx et http : //msdn.Microsoft.com/en-us/library/system.web.caching.cache.aspx ) persiste dans les configurations que vous avez configurées dans votre application.

voir par exemple "ASP.NET 4.0: Écriture de fournisseurs de cache de sortie personnalisés" http://weblogs.asp.net/gunnarpeipman/archive/2009/11/19/asp-net-4-0-writing-custom -output-cache-providers.aspx

3
Christian Westman