2009-12-18 7 views
0

désolé j'ai beaucoup de questions sur le verrou/cache. = _ = ..ce qui se passera si ne pas verrouiller le dictionnaire lorsque je le modifie? à propos du cache asp.net

-> 1. A propos de cache, je sais que le cache en asp.net est threadsafe, le code simple que je l'habitude d'utiliser est

IList<User> user= HttpRuntime.Cache["myCacheItem"] as IList<User>; 
    if (user == null) 
    { 
     //should i have a lock here? 
     //lock(some_static_var){...} 
     HttpRuntime.Cache["myCacheItem"] = GetDateFromDateBase(); 
    } 

    return user; 

devrait utiliser un verrou dans le code?

-> -> 1.1 si j'utilise, peut-être que je devrais déclarer beaucoup lockitem? J'ai vu une implémentation dans un serveur communautaire, il utilise un dictionnaire statique pour stocker le lockitem, est-ce une bonne idée? parce que je suis inquiet que ce soit peut-être trop de verrous dans le dictionnaire et peut-être ralentir le système.

-> -> 1.2 Si je ne l'utilise pas, que se passera-t-il? juste peut-être deux ou plusieurs threads accéder au GetDateFromDateBase()? si seulement cela, je pense que je peux peut-être abandonner le verrou.

-> 2.i j'ai un dictionnaire générique stocké dans le cache, je dois le modifier (ajouter/mettre à jour/supprimer). et je l'utilise juste pour obtenir la valeur comme dic.trygetvalue (key), ne la boucle pas.

-> -> 2.1 si je peux garantir que la modification est juste arriver un seul fil, la scène comme
a.aspx -> lire le dictionnaire du cache, et d'afficher sur la page, du public pour l'utilisateur
b.ashx -> va modifier le dictionnaire lorsque vous l'appelez (boucle en 5 minutes), privé utilisé

dois-je utiliser le verrouillage dans un/b? lecteur de verrouillage et écrivain?
-> -> -> 2.11 Si je n'utilise pas de verrou, que se passera-t-il? va-t-il lancer une exception quand le lecteur et l'auteur accèdent en même temps?
-> -> -> 2.12 Si je bloque juste l'écrivain dans b.ashx, que se passera-t-il? le lecteur de a.aspx sera-t-il bloqué? et quelle est la meilleure pratique pour faire face à cette situation?

-> -> 2.2 si le lecteur et l'écrivain se sont tous deux produits dans l'accès multi-threads. ils sont à la fois la page publique.
a.aspx -> il suffit de lire à partir du cache
b.aspx -> modifier le dictionnaire

quoi faire? verrouiller tout?

-> -> 2.3 si je mets en œuvre une nouvelle fonction ajouter le dictionnaire:
il suffit de copier le dictionnaire actuel à un nouveau dictionnaire, puis ajouter le nouvel élément ou modifier et enfin le retour de la nouvelle dic ,, sera -il résoudre le problème de concurrence?

la hashtable résoudra-t-elle ces problèmes?

comment déterminer qu'un article doit être verrouillé? Je pense que je me trompe dans ces choses = _ =.

-> 3.Le dernières question..i ont deux applications Web
un -> montrer le web
b -> mamage certains paramètres
ils ont tous deux propre cache, ce qui peut i en même temps les deux cache ?
l'opération dans [2.1] droite ou autre opération?(I test memcached mais trop lent que dans l'application web, donc je viens d'utiliser deux)

Merci de lire tous -_-...
souhaitez, vous pouvez savoir ce que je dis :)

Mise à jour ============================================== ========
Merci pour la réponse d'Aaron. après avoir lu sa réponse, j'essaie de me répondre :)
1. à propos du cache, si les données ne seront pas modifiées, il peut lire dans le cache d'abord dans Application_Start (global.asax).
1.1 Si le verrouillage, je devrais ajouter le démarrage de verrouillage lors de la lecture des données, non seulement l'écriture. l'élément de verrouillage doit être statique mais je me sens aussi désemparé à propos de 1.1.
1.2 Oui, si vous pouvez supposer que le code est simplement lu date de la base de données, puis insérer dans le cache et ne modifiera pas (droit? -_-). le résultat de ceci peut-être lu plusieurs fois de la base de données. Je pense que ce n'est pas un gros problème.

2. l'écriture du dictionnaire générique n'est pas threadsafe, elle devrait donc être verrouillée lors de la modification. Pour résoudre ce problème, je peux utiliser un dictionnaire immuable.
mais si j'utilise un ConcurrentDictionary (threadsafe lors de la lecture/écriture) dans .net4.0 ou je mets en œuvre un nouveau dictionnaire (mémorisez lecteur-graveur) moi-même, cela résoudra? Ai-je besoin de le verrouiller à nouveau lors de la modification? le code est comme

ConcurrentDictionary user= HttpRuntime.Cache["myCacheItem"] as ConcurrentDictionary; 
if (user == null) 
{ 
    //is it safe when the user is ConcurrentDictionary? 
    HttpRuntime.Cache["myCacheItem"] = GetDateFromDateBase(); 
} 
else 
{ 
    //is it safe when the user is ConcurrentDictionary? 
    user["1"] = a_new_user; 
} 


3.Le question est que, j'ai une petite application comme un Stroe, il a deux applications web un est le site d'exposition du magasin (A) et l'autre est la gestion site (B), donc je dois concourir deux cache web, comme ça si je modifie un prix de produit en B, comment puis-je informer le site A de changer/supprimer le cache? (Je sais que le cache dans A peut définir shortor, mais pas rapidement, donc je veux savoir quand il y a un support interne dans asp.net ou juste comme la question 2.1? avoir une page aspx/ashx à appeler?)

+0

Oui, vous devez verrouiller à la fois les lectures et les écritures. Si vous utilisez 'ConcurrentDictionary', vous n'avez pas besoin du verrou, mais assurez-vous d'utiliser les méthodes' AddOrUpdate'/'GetOrAdd', le cas échéant. Mais vous avez toujours une condition de concurrence sur l'élément cache lui-même, c'est pourquoi j'ai suggéré de l'initialiser dans 'Application_Start', donc vous n'avez jamais besoin de vérifier null. En ce qui concerne l'exigence de "partage" du cache, vous pouvez utiliser un 'SqlCacheDependency' si une base de données est mise à jour, sinon vous parlez d'IPC et je suggère de commencer une nouvelle question (ou mieux encore, en chercher une existante) . – Aaronaught

+0

merci encore :) – wingoo

Répondre

6

Filet-sûr signifie que vous n'avez pas e vous inquiétez que plusieurs threads lisent et écrivent le même élément de cache individuel en même temps. Vous n'avez besoin d'aucune sorte de verrou pour les lectures et les écritures simples. Cependant, si vous essayez d'effectuer une opération atomique - par exemple, en vérifiant la présence d'un élément et en l'ajoutant s'il n'existe pas, vous devez synchroniser ou sérialiser l'accès. Parce que le verrou doit être global, il est généralement préférable de déclarer un static readonly object dans votre global.asax et de le verrouiller avant d'effectuer l'opération atomique. Notez que vous devez verrouiller avant la lire et seulement libérer le verrou après la écriture, de sorte que votre serrure hypothétique dans votre exemple ci-dessus se passe réellement trop tard.

C'est pourquoi de nombreuses applications Web ne chargent pas le cache en mode différé; à la place, ils effectuent la charge dans la méthode Application_Start. À tout le moins, mettre un dictionnaire vide dans le cache vous épargnerait la peine de vérifier null, et de cette façon vous n'auriez pas à synchroniser car vous n'accéderiez à l'élément cache qu'une seule fois (mais lisez la suite).

L'autre aspect du problème est, même si le cache lui-même est thread-safe, il ne fait pas les éléments que vous ajoutez à ce thread-safe.Cela signifie que si vous stockez un dictionnaire, tous les threads qui récupèrent l'élément de cache obtiennent un dictionnaire entièrement initialisé, mais vous pouvez toujours créer des conditions de concurrence et d'autres problèmes de sécurité de threads si plusieurs demandes tentent d'accéder le dictionnaire concurremment avec au moins un d'entre eux le modifiant. Les dictionnaires dans .NET peuvent prendre en charge plusieurs lecteurs simultanés mais pas les écrivains. Vous pouvez donc rencontrer des problèmes si vous avez un seul dictionnaire stocké dans le cache ASP.NET et que vous avez plusieurs threads/requêtes en lecture et en écriture. Si vous pouvez garantir qu'un seul thread va écrire dans le dictionnaire, vous pouvez utiliser le dictionnaire comme un type immuable - c'est-à-dire copier le dictionnaire, modifier la copie et remplacer l'original dans le cache par la copie. Si le dictionnaire est rarement modifié, cela vous épargnera en effet la difficulté de synchroniser l'accès, car aucune requête n'essaiera jamais de lire le dictionnaire en cours de modification. D'un autre côté, si le dictionnaire est très volumineux et/ou fréquemment modifié, vous risquez de rencontrer des problèmes de performance en faisant toutes ces copies - la seule façon d'être sûr est le profil, le profil, le profil!

Si vous trouvez que les contraintes de performance ne permettent pas d'utiliser cette approche, alors la seule autre option est de synchroniser l'accès. Si vous savez qu'un seul thread va jamais modifier le dictionnaire à la fois, alors un verrou de lecteur-graveur (c'est-à-dire ReaderWriterLockSlim) devrait bien fonctionner pour vous. Si vous ne pouvez pas le garantir, alors vous avez besoin d'un Monitor (ou juste une simple clause lock(...) autour de chaque séquence d'opérations).

Cela devrait répondre aux questions 1-2; Je suis désolé mais je ne comprends pas très bien ce que vous demandez en # 3. Les applications ASP.NET sont toutes instanciées dans leurs propres AppDomains, donc il n'y a pas vraiment de problèmes de concurrence à proprement parler car rien n'est partagé (sauf si vous utilisez réellement une méthode IPC, auquel cas tout est juste).

Est-ce que j'ai bien compris vos questions? est-ce que cela aide?

+0

merci pour votre aide :) – wingoo