HTTPContext über threads
Brauche ich, um zu instanziieren Sie ein singleton-Objekt pro web-Anfrage, so dass die Daten einmal verarbeitet und ist gültig während der gesamten Anforderung, ich war mit HttpContext.Current.Items
zu teilen, die Daten während der HTTP-Anfrage, alles war gut, bis wir brauchten die singleton-Objekt-Instanz über mehrere threads, das erste, was ich kam mit war zu passieren, die HttpContext-Instanz für den neuen thread:
HttpContext context = HttpContext.Current;
ThreadPool.QueueUserWorkItem(callback =>
{
HttpContext.Current = context;
//blah blah
});
Was ich nicht glaube, ist eine thread-safe-Ansatz als hier angemerkt.
Mit dem Reflektor dachte ich HttpContext.Aktuelle.Elemente, die tatsächlich verwendet CallContext, um Objekte zu speichern, die in jeder logische thread. Also änderte ich die singleton-Schnittstelle:
public static SingletonType SingletonInstance
{
get { return CallContext.GetData(key) as SingletonType; }
set { CallContext.SetData(key, value); }
}
Und überschreiben Sie einfach SingletonInstance
beim Start jeder neuen thread! Der code funktioniert gut, aber es scheint, dass irgendwie unter der schweren Last, CallContext.GetData(key) den Wert null zurück und stürzt die Anwendung mit einem null-Verweis-Ausnahme!
Ich dachte, wenn CallContext.GetData
ist atomic? Aber es scheint einfach nicht richtig, die CallContext ist thread-spezifische Daten Speicher und muss atomar, oder mir fehlt der Punkt!
Meine andere Vermutung ist, dass die Einstellung der SingletonInstance (CallContext.SetData) passiert in einem thread, während CallContext.GetData führt, die in einem anderen als hier angemerkt aber ich weiß nicht, wie/warum?
update:
Halten wir eine Instanz von jedem online-Nutzer in einem array auf dem server. Das singleton-Objekt ist eigentlich ein Verweis auf das Objekt für den aktuellen Benutzer. Aktuellen Benutzers muss eindeutig sein und in jedem thread für die Datenbank-Abfragen, die Protokollierung, Fehlerbehandlung und mehr, dies ist, wie es gemacht wird:
public static ApplicationUser CurrentUser
{
get { return CallContext.GetData("ApplicationUser") as ApplicationUser ; }
set { CallContext.SetData("ApplicationUser", value); }
}
Das problem ist einfach, ich brauche ein einzelnes Objekt Referenz-in meinem applicatin instanziiert wird mit jeder Anfrage (Anwendung BeginRequest vielleicht) und lebendig ist, während die Anforderung, und jedem möglichen thread danach gestartet
InformationsquelleAutor Kamyar Nazeri | 2012-03-31
Du musst angemeldet sein, um einen Kommentar abzugeben.
ASP.NET möglicherweise migrieren Anforderung zwischen threads, wenn es unter Last. Sobald die Anfrage empfangen wird, Seite Konstruktor ausführen dürfen, in einem thread, und die Seite laden, die auf einem anderen. In diesem thread switch CallContext und ThreadStatic werden nicht migriert, aber luckaly HttpContext ist.
Dies kann irreführend sein, wie HttpContext-Anruf-Kontext, aber das ist eine kleine Macke in ASP.NET wahrscheinlich durch schneiden Ecken, um die Leistung zu verbessern.
Sie müssen entfernen Sie Abhängigkeiten von CallContext und verwenden HttpContext ganzen Weg durch.
Lesen Sie mehr details in diesem toller blog-post von Piers7.
Ich sehe nicht, zu viele Optionen. Sie müssen entweder 1) alle Daten, die Sie brauchen, um Ihre Methode, wenn queuing es zu ThreadPool oder 2) tatsächlich das senden HttpContext und vorsichtig mit ihm. Hast du link zu einer Frage ALSO, die Staaten, die diese "nicht thread-safe". Dieser Vorgang ist thread-sicher, und Sie senden die richtigen HttpContext-Instanz, aber die Sammlung, die er hält ist nicht thread-sicher, so dass Sie müssen vorsichtig sein, wie Sie darauf zugreifen. Um auf der sicheren Seite, vielleicht Sie konnten es vermeiden, die Zuordnung zu HttpContext.Strom im worker-thread, und es direkt benutzen, oder zumindest die Reinigung bis nach dem Arbeitnehmer gemacht wird.
InformationsquelleAutor Nikola Radosavljević
Dieser wurde behoben, die während einer chat-Sitzung.
Im wesentlichen beinhaltet es langzeitaufgaben und einen Vorschlag mit einem externen Dienst (Web, oder ein regulärer Windows-Dienst) wurde beschlossen, die beste Lösung für das problem.
siehe meine aktualisierte Antwort. Instanziieren Sie diese am Anfang der Anfrage, und zerstören es am Ende. Es ist thread-safe.
Was ist, wenn die Anforderung endet, bevor ein anderer thread/threads beenden? in diesem Fall muss ich verfolgen jeden thread und irgendwie entsorgen Sie den cache, wenn der Letzte thread beendet! Irgendwo zwischen einem weiteren Antrag schlagen konnten Sie die Anwendung und schreiben falsche Daten zum cache! natürlich haben verschiedene Schlüssel für verschiedene Benutzer/Anfrage ist ein weiteres Problem, das braucht zusätzliche Aufmerksamkeit!
vielleicht kann man das erweitern auf das, was es ist, du bist eigentlich tun zu machen diese?
überprüfen Sie heraus das update im original-post
InformationsquelleAutor Moo-Juice
Thread-safing Ihrem zweiten Methode, der beste Ansatz.
Dieser ist thread-safe version Ihrer singletone:
HINWEIS : die Verwendung eines
lock { }
block ist der Schlüssel.Ich denke, dass null-Werte zurückgegeben, die von CallContext werden, weil zwei threads setzen callContext-Taste gleichzeitig. und [vielleicht] etwas schief geht, innerhalb CallContext.SetData()... Also schließ es verwaltet wird. und es ist kein performance-Problem. Sie können test. vielleicht die null-Werte verschwinden. BTW ich habe es nicht selbst ausprobiert. Sperren nicht sperren, ein Feld oder eine Eigenschaft oder etwas anderes. sperrt es einen code-block. Ich denke, es ist eine bessere Implementierung für den zweiten Ansatz
Wenn Sie einen Blick auf .net-Quellcode referencesource.microsoft.com/#mscorlib/system/runtime/remoting/... Sie werden bemerken, dass die
SetData
Methode tatsächlich Gebrauch macht, ist derThread.CurrentThread
um eine Kostenlose Daten-slot. So gibt es keine Zeitgleichheit hier und kein Schloss-nichtsOk, war eine Vermutung. Aber warum CallContext ist null zurückgeben manchmal? Und was war deine Letzte Lösung
CallContext ist nicht eine gute option in der Asp.net Anwendung, um mit zu beginnen. Stellt sich heraus, unter Last ASP.Net migrieren, können eingehende Anfragen der IO-threadpool in die Warteschlange aufgenommen, indem es die thread-pool worker-Prozess. d.h. deine Wunsch-thread kann nicht das gleiche in der gesamten asp-pipeline. als Nikola Radosavljević wies darauf hin, Lesen Sie mehr hier: piers7.blogspot.fr/2005/11/threadstatic-callcontext-and_02.html
InformationsquelleAutor abzarak