Mise à jour: ASP.NET Core n'a pas deSynchronizationContext
. Si vous êtes sur ASP.NET Core, peu importe que vous l'utilisiez ConfigureAwait(false)
ou non.
Pour ASP.NET "Full" ou "Classic" ou autre, le reste de cette réponse s'applique toujours.
Message d'origine (pour ASP.NET non-Core):
Cette vidéo de l'équipe ASP.NET contient les meilleures informations sur l'utilisation async
sur ASP.NET.
J'avais lu qu'il est plus performant car il n'a pas à basculer les contextes de thread vers le contexte de thread d'origine.
Cela est vrai avec les applications d'interface utilisateur, où il n'y a qu'un seul thread d'interface utilisateur sur lequel vous devez "synchroniser".
Dans ASP.NET, la situation est un peu plus complexe. Lorsqu'une async
méthode reprend l'exécution, elle récupère un thread du pool de threads ASP.NET. Si vous désactivez la capture de contexte à l'aide ConfigureAwait(false)
, le thread continue simplement d'exécuter la méthode directement. Si vous ne désactivez pas la capture de contexte, le thread ré-entrera dans le contexte de la demande et continuera ensuite à exécuter la méthode.
Donc, ConfigureAwait(false)
ne vous enregistre pas un saut de fil dans ASP.NET; cela vous évite de rentrer dans le contexte de la demande, mais cela est normalement très rapide. ConfigureAwait(false)
pourrait être utile si vous essayez de faire une petite quantité de traitement parallèle d'une demande, mais en réalité, TPL est mieux adapté à la plupart de ces scénarios.
Cependant, avec ASP.NET Web Api, si votre demande arrive sur un thread et que vous attendez une fonction et appelez ConfigureAwait (false) qui pourrait potentiellement vous mettre sur un autre thread lorsque vous renvoyez le résultat final de votre fonction ApiController .
En fait, juste faire un await
peut le faire. Une fois que votre async
méthode atteint un await
, la méthode est bloquée mais le thread retourne au pool de threads. Lorsque la méthode est prête à continuer, tout thread est extrait du pool de threads et utilisé pour reprendre la méthode.
La seule différence ConfigureAwait
dans ASP.NET est de savoir si ce thread entre dans le contexte de la demande lors de la reprise de la méthode.
J'ai plus d'informations de fond dans mon article MSDN surSynchronizationContext
et mon async
blog d'introduction .
HttpContext.Current
est acheminé par ASP.NETSynchronizationContext
, qui est acheminé par défaut lorsque vousawait
, mais il n'est pas acheminé parContinueWith
. OTOH, le contexte d'exécution (y compris les restrictions de sécurité) est le contexte mentionné dans CLR via C #, et il est transmis par les deuxContinueWith
etawait
(même si vous utilisezConfigureAwait(false)
).ConfigureAwait
n'a de sens que lorsque vous attendez des tâches , alors qu'ilawait
agit sur tout "en attente". Les autres options envisagées étaient les suivantes: le comportement par défaut doit-il ignorer le contexte s'il se trouve dans une bibliothèque? Ou avez-vous un paramètre de compilation pour le comportement de contexte par défaut? Les deux ont été rejetés car il est plus difficile de simplement lire le code et de dire ce qu'il fait.ConfigureAwait(false)
d'éviter un blocage basé surResult
/Wait
car sur ASP.NET, vous ne devriez pas utiliserResult
/Wait
en premier lieu.Réponse brève à votre question: Non. Vous ne devriez pas appeler
ConfigureAwait(false)
au niveau de l'application comme ça.Version TL; DR de la réponse longue: Si vous écrivez une bibliothèque où vous ne connaissez pas votre consommateur et n'avez pas besoin d'un contexte de synchronisation (ce que vous ne devriez pas dans une bibliothèque, je crois), vous devez toujours utiliser
ConfigureAwait(false)
. Sinon, les consommateurs de votre bibliothèque peuvent faire face à des blocages en consommant vos méthodes asynchrones de manière bloquante. Cela dépend de la situation.Voici une explication un peu plus détaillée sur l'importance de la
ConfigureAwait
méthode (une citation de mon article de blog):En outre, voici deux excellents articles pour vous qui sont exactement pour votre question:
Enfin, il y a une excellente courte vidéo de Lucian Wischik sur ce sujet: les méthodes de bibliothèque asynchrone devraient envisager d'utiliser Task.ConfigureAwait (false) .
J'espère que cela t'aides.
la source
Task
marche la pile pour obtenir leSynchronizationContext
, ce qui est faux. LeSynchronizationContext
est saisi avant l'appel à laTask
, puis le reste du code se poursuit sur leSynchronizationContext
ifSynchronizationContext.Current
n'est pas nul.SynchronizationContext.Current
c'est clair / ou que la bibliothèque est appelée dans unTask.Run()
au lieu d'avoir à écrire.ConfigureAwait(false)
partout dans la bibliothèque de classe?.ConfigureAwait(false)
art. Il serait peut-être plus facile pour les auteurs de bibliothèques si tel était le comportement par défaut, mais je présume qu'il est un peu plus difficile d'écrire une bibliothèque correctement que de rendre un peu plus difficile l'écriture d'une application correctement.Le plus grand inconvénient que j'ai trouvé avec l'utilisation de ConfigureAwait (false) est que la culture de thread est rétablie par défaut. Si vous avez configuré une culture, par exemple ...
et que vous hébergez sur un serveur dont la culture est définie sur en-US, vous trouverez avant que ConfigureAwait (false) ne s'appelle CultureInfo.CurrentCulture renverra en-AU et après que vous obtiendrez en-US. c'est à dire
Si votre application fait quelque chose qui nécessite un formatage de données spécifique à la culture, vous devrez en être conscient lors de l'utilisation de ConfigureAwait (false).
la source
ConfigureAwait(false)
est utilisée.J'ai quelques réflexions générales sur la mise en œuvre de
Task
:using
.ConfigureAwait
a été introduit en 4.5.Task
a été introduit en 4.0.Task.ContinueWith
ils ne sont pas b / c, il a été réalisé que le changement de contexte est coûteux et il est désactivé par défaut.J'ai quelques articles sur le sujet, mais mon point de vue - en plus de la belle réponse de Tugberk - est que vous devez activer toutes les API asynchrones et idéalement gérer le contexte. Puisque vous effectuez une async, vous pouvez simplement utiliser des continuations au lieu d'attendre, donc aucun blocage ne sera causé car aucune attente n'est effectuée dans la bibliothèque et vous gardez le flux afin que le contexte soit préservé (tel que HttpContext).
Le problème est lorsqu'une bibliothèque expose une API synchrone mais utilise une autre API asynchrone - vous devez donc utiliser
Wait()
/Result
dans votre code.la source
Task.Dispose
si vous le souhaitez; vous n'avez tout simplement pas besoin de la grande majorité du temps. 2) aTask
été introduit dans .NET 4.0 dans le cadre du TPL, ce qui n'était pas nécessaireConfigureAwait
; une foisasync
ajouté, ils ont réutilisé leTask
type existant au lieu d'en inventer un nouveauFuture
.Task
s; le "contexte" contrôlé parContinueWith
est unSynchronizationContext
ouTaskScheduler
. Ces différents contextes sont expliqués en détail sur le blog de Stephen Toub .Thread
s, mais plus avecContinueWith()
), cela rend votre réponse confuse à lire.