Arrière-plan:
Je maintiens plusieurs applications Winforms et les bibliothèques de classes pouvant ou déjà faire bénéficier de la mise en cache. Je suis également au courant de la mise en Cache de Bloc d'Application et le Système.Web.La mise en cache de noms (qui, d'après ce que j'ai recueillies, est parfaitement OK pour utilisation à l'extérieur ASP.NET).
J'ai trouvé que, bien que les deux classes ci-dessus sont techniquement "thread-safe" dans le sens que les méthodes individuelles sont synchronisés, ils n'ont pas vraiment l'air d'être conçu particulièrement pour le multi-thread scénarios. Plus précisément, ils ne sont pas en œuvre un GetOrAdd
méthode similaire à celle de la nouvelle - ConcurrentDictionary
classe .NET 4.0.
Nous pensons qu'une telle méthode soit une primitive de cache et de la fonctionnalité de recherche, et, évidemment, le Cadre designers, conscience de ce trop - c'est pourquoi les méthodes existent dans la concurrente de collections. Cependant, hormis le fait que je ne suis pas à l'aide .NET 4.0 dans la production d'applications encore, un dictionnaire n'est pas un véritable cache - elle n'a pas de caractéristiques comme des expirations, persistant/stockage distribué, etc.
Pourquoi c'est important:
Un assez typique de la conception dans un "client riche" de l'app (ou même des applications web) est de commencer pré-chargement d'un cache dès que l'application démarre, le blocage si le client demande des données qui n'est pas encore chargé (suite de la mise en cache pour une utilisation ultérieure). Si l'utilisateur est de labourer par le biais de son flux de travail rapidement, ou si la connexion réseau est lente, il n'est pas rare du tout pour le client d'être en concurrence avec le preloader, et il n'a vraiment pas beaucoup de sens de demander deux fois les mêmes données, en particulier si la demande est relativement cher.
Alors il me semble d'être de gauche avec un peu de tout aussi moche options:
N'essayez pas de faire l'opération atomique à tous, et le risque de les données en cours de chargement deux fois (et peut-être avoir deux threads différents exploitation sur différentes copies);
Sérialiser l'accès à la mémoire cache, ce qui signifie que le verrouillage de l' intégralité du cache pour charger un seul élément;
Début de réinventer la roue, juste pour obtenir un supplément de quelques méthodes.
Précisions: Exemple De Montage
Dire que lorsque l'application démarre, il doit charger 3 les ensembles de données qui chaque de prendre 10 secondes pour charger. Réfléchissez à ces deux échéances:
00:00 - Commencer le chargement Dataset 1 00:10 - Démarrer le chargement Dataset 2 00:19 - Utilisateur en fait la demande Dataset 2
Dans le cas ci-dessus, si nous n'utilisons pas de tout type de synchronisation, l'utilisateur doit attendre 10 secondes pour les données qui seront disponibles dans 1 seconde, parce que le code va voir que l'article n'est pas encore chargé dans le cache et essayez de la recharger.
00:00 - Commencer le chargement Dataset 1 00:10 - Démarrer le chargement Dataset 2 00:11 - l'Utilisateur demande de l'ensemble de données 1
Dans ce cas, l'utilisateur est en demandant des données qui est déjà dans le cache. Mais si nous sérialiser l'accès à la cache, il va falloir attendre encore 9 secondes pour aucune raison du tout, parce que le gestionnaire de cache (quelle qu'elle soit) n'a pas de prise de conscience de l' élément spécifique demandé, seulement que "quelque chose" est demandée et de "quelque chose" est en cours.
La Question:
Existe-il des bibliothèques de mise en cache pour .NET (pré-4.0) qui n' mettre en œuvre de telles opérations atomiques, que l'on peut attendre d'un thread-safe cache?
Ou sinon, est-il un moyen de prolonger l'existant "thread-safe" cache à l'appui de telles opérations, sans la sérialisation des accès à la mémoire cache (ce qui irait à l'encontre de l'objectif de l'utilisation d'un thread-safe mise en œuvre en premier lieu)? Je doute qu'il y est, mais peut-être que je suis juste fatigué et en ignorant une solution évidente.
Ou... est-il autre chose que je suis absent? Est-il juste de pratique courante de laisser deux concurrents fils steamroll les uns des autres si elles se produisent à la fois demander le même article, dans le même temps, pour la première fois ou après une date d'expiration?