HTTPContext sur les threads
J'ai besoin d'instancier un objet singleton par requête web, de sorte que les données sont traitées en une seule fois et est valable tout au long de la demande, j'ai été en utilisant HttpContext.Current.Items
de partager des données lors de la requête HTTP, tout allait bien jusqu'à ce que nous avions besoin de l' singleton instance de l'objet entre plusieurs threads, la première chose que j'ai trouvé a été de passer de l'instance HttpContext pour le nouveau thread:
HttpContext context = HttpContext.Current;
ThreadPool.QueueUserWorkItem(callback =>
{
HttpContext.Current = context;
//blah blah
});
Qui je ne pense pas qu'est un thread-safe approche noter ici.
L'aide d'un Réflecteur, j'ai pensé HttpContext.Actuel.Les éléments utilise CallContext pour stocker les objets dans chaque thread logique. J'ai donc changé le singleton interface:
public static SingletonType SingletonInstance
{
get { return CallContext.GetData(key) as SingletonType; }
set { CallContext.SetData(key, value); }
}
Et il suffit de remplacer SingletonInstance
lors du démarrage d'un nouveau thread! Le code fonctionne très bien, cependant, il semble que d'une certaine façon sous une lourde charge, CallContext.GetData(clé) renvoie la valeur null et l'application se bloque avec une référence nulle exception!
Que je pensais, si CallContext.GetData
est atomique? Mais il ne semble pas approprié, le CallContext est thread spécifique de stockage de données et doit être atomique ou je suis à côté de la question!
Mon autre supposition est que la définition de la SingletonInstance (CallContext.SetData) arrive dans un thread pendant que CallContext.GetData s'exécute dans un autre comme noter ici mais je ne sais pas comment/pourquoi?
mise à jour:
Nous gardons une instance de chaque utilisateur en ligne dans un tableau sur le serveur. L'objet singleton est en fait une référence à l'objet représentant actuel de l'utilisateur. L'utilisateur actuel doit être unique et disponible dans chaque thread pour l'interrogation de bases de données, l'exploitation forestière, la gestion d'erreur et de plus, c'est comment il est fait:
public static ApplicationUser CurrentUser
{
get { return CallContext.GetData("ApplicationUser") as ApplicationUser ; }
set { CallContext.SetData("ApplicationUser", value); }
}
Le problème est simple, j'ai besoin d'une seule référence d'objet dans mon application iphone qui est instancié avec la demande (Demande BeginRequest peut-être), et il est vivant tout au long de la demande, et possible thread qui a commencé par la suite
OriginalL'auteur Kamyar Nazeri | 2012-03-31
Vous devez vous connecter pour publier un commentaire.
ASP.NET peut migrer demande entre les threads si c'est sous la charge. Une fois que la demande est reçue constructeur de page peut exécuter sur un fil et de chargement de la page sur l'autre. Dans ce fil, commutateur CallContext et ThreadStatic ne sont pas migrés, mais luckaly HttpContext.
Cela peut être trompeur, car HttpContext est le contexte d'appel, mais c'est un peu de bizarrerie dans ASP.NET, probablement en raison de couper les coins pour améliorer les performances.
Vous devrez supprimer des dépendances à CallContext et l'utilisation HttpContext tout le chemin à travers.
Vous pouvez lire plus de détails dans ce formidable blog par Piers7.
Je ne vois pas trop d'options. Vous avez besoin soit de 1) passer toutes les données dont vous avez besoin pour votre méthode lorsque les files d'attente à pool de threads ou 2) l'envoi HttpContext et d'être prudent avec elle. Vous avez un lien vers la question qui stipule ce "n'est pas thread-safe". Cette opération est thread-safe, et vous enverra corriger HttpContext exemple, mais la collection qu'il détient n'est pas thread-safe, donc vous devez être prudent sur la manière d'y accéder. Pour être sur le côté sûr, peut-être vous petit plus ponctuellement éviter d'attribuer à HttpContext.Courant dans le thread de travail, et de l'utiliser directement, ou au moins la nettoyer après travailleur est fait.
OriginalL'auteur Nikola Radosavljević
Cela a été résolu au cours d'une session de chat.
En substance, il s'implique à long tâches en cours d'exécution et une suggestion de l'utilisation d'un service externe (Web, ou de Fenêtres régulières de Service) a été décidé que la meilleure solution au problème.
voir ma réponse mis à jour. Instancier au début de la demande, et de le détruire à la fin. C'est thread-safe.
Que faire si la demande se termine avant qu'un autre thread/threads terminer le travail? dans ce cas, j'ai besoin de garder une trace de chaque thread et en quelque sorte à éliminer le cache lorsque le dernier thread se termine! Quelque part entre une autre demande peut frapper l'application et d'écrire des données erronées dans le cache! bien sûr, d'avoir des clés différentes pour les différents utilisateurs/demande est une autre question qui a besoin d'attention supplémentaire!
peut-être que vous pouvez développer sur ce que vous êtes réellement faire pour l'exigent?
découvrez la mise à jour dans le post original
OriginalL'auteur Moo-Juice
Thread-safing votre deuxième méthode est la meilleure approche.
C'est la version thread-safe de votre singletone:
REMARQUE : l'utilisation d'un
lock { }
bloc est la clé.Je pense que les valeurs null est retourné à partir de CallContext sont parce que les deux fils sont callContext clés en même temps. et [peut-être] quelque chose se passe mal à l'intérieur de CallContext.SetData()... Donc de verrouillage va gérer ça. et il n'y a pas de problème de performance avec elle. Vous pouvez tester. peut-être que les valeurs null disparaître. BTW, je n'ai pas testé moi-même. Le verrouillage n'est pas verrouiller un champ ou une propriété ou quelque chose d'autre. il verrouille un bloc de code. Je pense juste que c'est une meilleure mise en œuvre de votre deuxième approche
Si vous prenez un coup d'oeil .net code source referencesource.microsoft.com/#mscorlib/system/runtime/remoting/... vous remarquerez que le
SetData
méthode réellement fait usage deThread.CurrentThread
pour obtenir gratuitement des données de la fente. Donc, il n'y a pas de simultanéité et pas besoin de verrouiller rienOk c'était une supposition. Mais pourquoi CallContext est de retour null, parfois? Et quelle a été votre solution finale
CallContext n'est pas une bonne option Asp.net application de commencer avec. S'avère, sous la charge ASP.Net pouvez migrer les demandes entrantes à partir de son IO pool de threads à une file d'attente prises par ses processus de travail du pool de threads. par exemple, votre demande de fil peut ne pas être la même tout au long de l'asp pipeline. comme Nikola Radosavljević souligné, vous pouvez en lire plus ici: piers7.blogspot.fr/2005/11/threadstatic-callcontext-and_02.html
OriginalL'auteur abzarak