2010-04-14 5 views
13

ich Cache in einer Web-Service-Methode wie folgt bin mit:Mit 'HttpContext.Current.Cache' sicher

var pblDataList = (List<blabla>)HttpContext.Current.Cache.Get("pblDataList"); 

if (pblDataList == null) 
{ 
    var PBLData = dc.ExecuteQuery<blabla>(@"SELECT blabla"); 

    pblDataList = PBLData.ToList(); 

    HttpContext.Current.Cache.Add("pblDataList", pblDataList, null, 
     DateTime.Now.Add(new TimeSpan(0, 0, 15)), 
     Cache.NoSlidingExpiration, CacheItemPriority.Normal, null); 
} 

Aber ich frage mich, ist dieser Code Thread-sicher? Die Web-Service-Methode wird von mehreren Anforderern aufgerufen. Und mehr als ein Anforderer kann versuchen, Daten abzurufen und zur Cache zur gleichen Zeit hinzuzufügen, während der Cache leer ist.

Die Abfrage dauert 5 bis 8 Sekunden. Würde die Einführung einer Lock-Anweisung um diesen Code mögliche Konflikte verhindern? (Ich weiß, dass mehrere Abfragen gleichzeitig ausgeführt werden können, aber ich möchte sicherstellen, dass immer nur eine Abfrage ausgeführt wird.)

Antwort

22

Das Cache-Objekt ist thread-sicher , aber HttpContext.Current wird nicht von Hintergrundthreads verfügbar sein. Dies kann oder kann nicht auf Sie zutreffen, es ist nicht offensichtlich aus Ihrem Code-Snippet, ob Sie tatsächlich Hintergrund-Threads verwenden oder nicht, aber für den Fall, dass Sie jetzt oder zu einem späteren Zeitpunkt entscheiden, sollten Sie dies im Hinterkopf behalten .

Wenn es eine Chance gibt, dass Sie von einem Hintergrundthread auf den Cache zugreifen müssen, verwenden Sie stattdessen HttpRuntime.Cache.

Obwohl einzelne Operationen im Cache Thread-sicher sind, sind sequenzielle Lookup/Store-Operationen offensichtlich nicht atomar. Ob Sie brauchen, um atomar zu sein, hängt von Ihrer speziellen Anwendung ab. Wenn es ein schwerwiegendes Problem sein könnte, dass die gleiche Abfrage mehrmals ausgeführt wird, dh wenn sie mehr Last erzeugt, als Ihre Datenbank verarbeiten kann, oder wenn es ein Problem für eine Anforderung wäre, Daten zurückzugeben, die sofort in der Datenbank überschrieben werden Cache, dann würden Sie wahrscheinlich eine Sperre um den gesamten Codeblock platzieren möchten.

In den meisten Fällen möchten Sie jedoch wirklich zuerst Profil und sehen, ob das tatsächlich ein Problem ist. Die meisten Webanwendungen/Dienste befassen sich nicht mit diesem Aspekt des Caching, da sie zustandslos sind und es keine Rolle spielt, ob der Cache überschrieben wird.

+0

Ich verwende keine Hintergrund-Threads, es sind nur Web-Service-Anrufe. Übrigens, danke. –

2

Sie haben Recht. Die Abruf- und Addiervorgänge werden nicht als atomare Transaktion behandelt. Wenn Sie verhindern müssen, dass die Abfrage mehrmals ausgeführt wird, müssen Sie eine Sperre verwenden.

(Normalerweise wäre dies nicht ein Problem viel, aber im Fall einer Abfrage mit langer Laufzeit kann es nützlich sein, Belastung für die Datenbank zu entlasten.)

+2

Das hängt wirklich davon ab. In einer Umgebung mit hohem Durchsatz ist die zusätzliche Belastung der Datenbank möglicherweise nicht so groß wie die Anforderung, die sich aus dieser Art der Sperrung ergibt.In den meisten Fällen würde ich sagen, dass Sie Recht haben, aber jeder Fall muss individuell bewertet werden. – Aaronaught

+0

Guter Punkt. Ich habe meine Antwort deswegen leicht umformuliert. – Greg

1

glaube ich, die Add Thread-sicher sein sollte - dh es wird kein Fehler, wenn Add wird zweimal mit dem gleichen Schlüssel aufgerufen, aber offensichtlich könnte die Abfrage zweimal ausführen.

Eine andere Frage ist jedoch ist die Daten Thread-Safe. Es gibt keine Garantie, dass jeder List<blabla> isoliert ist - es hängt vom Cache-Provider ab. Der speicherinterne Cache-Provider speichert die Objekte direkt. Es besteht daher die Gefahr von Kollisionen, wenn einer der Threads die Daten bearbeitet (Elemente in der Liste hinzufügen/entfernen/auslagern oder Eigenschaften eines Elements ändern). Aber mit einem Serialisierung Anbieter sollten Sie in Ordnung sein. Natürlich erfordert dies dann, dass blabla serialisierbar ist ...

+0

Können Sie einen Link zum Serialisieren Ihres Objekts für den Cache freigeben? Ich habe versucht, eine Datentabelle bei der Arbeit für einen Web-Bildschirm zwischenzuspeichern, der einige Daten filtert. Mir wurde gesagt, dass die Serverlast zu viel wäre. Kennen Sie Artikel, in denen es um Caching und Serialisierung sowie um die Serverbelastung geht? Beim Googlen konnte ich nichts Bestimmtes finden. –

+0

@kcbeard Erstens, einmal zwischengespeichert: ** nicht mutieren ** eine 'DataTable'. Jetzt ist das aus dem Weg: Wie groß sind die Daten? Welches Zeilenvolumen? –

+0

Überall von ein paar hundert Reihen bis 5k max. Ein Dutzend Spalten mit den Datentypen date-time, int und var-char. Der gesunde Menschenverstand sagte mir, ich solle den Blick nicht benutzen und SO unterstützte mich. Ich war unter der Annahme, dass nur ein paar Benutzer pro Anwendungsinstanz darauf zugreifen würden, also benutzte ich zuerst Current.Session, dann wurde die Serverlast heraufgebracht, zu viel war ich also Current.Cache (App weit). Ich meine, vielleicht wäre eine gespeicherte Prozedur flexibel genug, um mit allen Filterungen fertig zu werden. Aber so oder so möchte ich mehr über Caching-Sicherheit, Best Practices, Fallstricke usw. wissen. –