Quelles sont les différences entre l'utilisation de ConfigureAwait(faux) et de la Tâche.Exécuter?
Je comprends qu'il est recommandé d'utiliser ConfigureAwait(false)
pour await
s dans la bibliothèque de code, de sorte que le code suivant ne fonctionne pas en l'appelant du contexte d'exécution, ce qui pourrait être un thread d'INTERFACE utilisateur. Je comprends aussi que await Task.Run(CpuBoundWork)
doit être utilisé au lieu de CpuBoundWork()
pour la même raison.
Exemple avec ConfigureAwait
public async Task<HtmlDocument> LoadPage(Uri address)
{
using (var client = new HttpClient())
using (var httpResponse = await client.GetAsync(address).ConfigureAwait(false))
using (var responseContent = httpResponse.Content)
using (var contentStream = await responseContent.ReadAsStreamAsync().ConfigureAwait(false))
return LoadHtmlDocument(contentStream); //CPU-bound
}
Exemple avec Task.Run
public async Task<HtmlDocument> LoadPage(Uri address)
{
using (var client = new HttpClient())
using (var httpResponse = await client.GetAsync(address))
return await Task.Run(async () =>
{
using (var responseContent = httpResponse.Content)
using (var contentStream = await responseContent.ReadAsStreamAsync())
return LoadHtmlDocument(contentStream); //CPU-bound
});
}
Quelles sont les différences entre ces deux approches?
Vous devez vous connecter pour publier un commentaire.
Quand vous dites
Task.Run
, vous dites que vous avez de l'UC du travail à faire, cela peut prendre un long moment, donc il devrait toujours être exécuté sur un thread du pool.Quand vous dites
ConfigureAwait(false)
, vous dites que le reste de laasync
méthode n'a pas besoin du contexte d'origine.ConfigureAwait
est plus un indicateur d'optimisation; il n'a pas toujours dire que la suite est exécuté sur un thread du pool.LoadHtmlDocument
est de parser le HTML; cette analyse ne doit pas être fait sur le thread de l'INTERFACE utilisateur, de sorte qu'il n'a pas besoin de contexte.async
méthode de mise à jour d'unLabel
ouProgressBar
, alors il serait nécessaire de reprendre dans le contexte de l'INTERFACE utilisateur. Si elle ne le faisait pas, il serait d'obtenir un cross-thread exception.ConfigureAwait(false)
fait dire que le contexte d'origine (je suppose que tu veux dire SynchronizationContext) n'est pas nécessaire ou n'est-ce à dire que la continuation ne doit pas et ne seront pas être exécuté à l'origine, contexte de synchronisation. Je pense que le dernier est le cas. Si c'était juste un soupçon, il n'y a aucun moyen de déterminer si la suite sera exécuté à l'origine, contexte de synchronisation, ou pas, introduisant ainsi un comportement indéfini, et probablement les blocages.async
intro: le courantSynchronizationContext
ouTaskScheduler
. C'est un indice, mais il est en effet si la tâche n'est pas terminée. Il n' pas changement des contextes si la tâche est déjà terminé (par exemple, le résultat a été lu à partir d'un cache). Si vous avez le code que doit exécuter sur le pool de threads,Task.Run
est le plus approprié.ConfigureAwait(false)
n'est pas suffisant car si la tâche est déjà terminée, la continuation de ne pas utiliser le contenu, non? Dans ce cas, je doit envelopper la continuation de la tâche dans unTask.Run
pour assurer l'exécution dans le pool de threads.GetDataAsync2
faites-vous allusion?LoadPage
commence à s'exécuter dans.Dans ce cas, votre
Task.Run
version aura un peu plus de surcharge, comme les premiers attendent appel (await client.GetAsync(address)
) sera toujours maréchal de nouveau dans le contexte de l'appel, ainsi que les résultats de laTask.Run
appel.Dans le premier exemple, sur l'autre main, votre premier
Async()
méthode est configuré pour ne pas nécessiter de marshaling de nouveau dans le contexte de l'appel, ce qui permet la continuation de s'exécuter sur un thread d'arrière-plan encore. En tant que tel, il n'y aura pas de regroupement de retour en l'appelant contexte.Convenu @Stephen réponse, Si elle est encore la confusion voir ci-dessous les captures d'écran
1# Sans ConfigureAwait(faux)
Voir l'image ci-dessous thread Principal essayer de mettre à jour l'Étiquette
2# Avec ConfigureAwait(faux)
Voir l'image ci-dessous thread de travail tente de mettre à jour l'étiquette
Comme une note de côté, dans les deux cas
LoadPage()
pourrait encore bloquer votre thread de l'INTERFACE utilisateur, parce queawait client.GetAsync(address)
a besoin de temps pour créer une tâche de passer àConfigureAwait(false)
. Et votre temps de fonctionnement peut-être déjà commencé avant que la tâche est retourné.Une solution possible est d'utiliser
SynchronizationContextRemover
de ici: