J'utilise HttpClient pour publier des données sur un service distant dans un projet .NET 4.0. Je ne suis pas concerné par le blocage de cette opération, j'ai donc pensé que je pouvais ignorer ContinueWith ou async/wait et utiliser Result.
Lors du débogage, j'ai rencontré un problème où le serveur distant n'était pas réactif. Alors que je parcourais le code, il semblait que mon code venait de s'arrêter sur la troisième ligne ... la ligne actuelle du pointeur de pile a cessé d'être surlignée en jaune et n'a pas avancé à la ligne suivante. Il a juste disparu. Il m'a fallu un certain temps pour réaliser que je devais attendre que la demande expire.
var client = new HttpClient();
var task = client.PostAsync("http://someservice/", someContent);
var response = task.Result;
Ma compréhension était que l'appel de Result sur la tâche faisait que le code s'exécutait de manière synchrone, se comportait plus comme ceci (je sais qu'il n'y a pas de méthode Post dans HttpClient):
var client = new HttpClient();
var response = client.Post("http://someservice/", someContent);
Je ne suis pas sûr que ce soit une mauvaise chose, j'essaie juste de comprendre. Est-il vraiment vrai qu'en raison du fait que le HttpClient renvoie directement des tâches au lieu des résultats, mon application profite automatiquement de l'asynchronie même lorsque je pense que je l'évite?
Sous Windows, toutes les E/S sont asynchrones. Les API synchrones ne sont qu'une abstraction pratique.
Ainsi, lorsque vous utilisez HttpWebRequest.GetResponse
, Ce qui se passe réellement, c'est que les E/S sont démarrées (de manière asynchrone) et le thread appelant (de manière synchrone) se bloque, en attendant qu'il se termine.
De même, lorsque vous utilisez HttpClient.PostAsync(..).Result
, les E/S sont démarrées (de manière asynchrone) et le thread appelant (de manière synchrone) se bloque, en attendant qu'il se termine.
Je recommande généralement aux gens d'utiliser await
plutôt que Task.Result
Ou Task.Wait
Pour les raisons suivantes:
Task
qui est le résultat d'une méthode async
, vous pouvez entrer facilement dans une situation de blocage .Task.Result
Et Task.Wait
Encapsulent toutes les exceptions dans un AggregateException
(car ces API sont des restes du TPL). La gestion des erreurs est donc plus complexe.Cependant, si vous êtes conscient de ces limitations, il existe certaines situations où le blocage sur un Task
peut être utile (par exemple, dans le Main
d'une application console).
La capture du résultat d'une tâche bloque le thread actuel. Il est inutile d'utiliser une version asynchrone d'une méthode dans ce cas. Post()
et PostAsync().Result
bloqueront tous les deux.
Si vous souhaitez utiliser la simultanéité, vous devez l'écrire comme telle:
async Task PostContent()
{
var client = new HttpClient();
Task t = await client.PostAsync("http://someservice/", someContent);
//code after this line will execute when the PostAsync completes.
return t;
}
Puisque PostContent()
lui-même renvoie une tâche, la méthode qui l'appelle doit également attendre.
async void ProcessResult()
{
var result = await PostContent();
//Do work with the result when the result is ready
}
Par exemple, si vous appelez ProcessResult()
dans un gestionnaire de clic de bouton, vous voyez que l'interface utilisateur est toujours sensible, d'autres contrôles fonctionnent toujours.