Lors de ma lecture sur la programmation asynchrone dans .Net 4.5 async
et await
mots-clés, j'ai lu ici le paragraphe suivant
Traitement des demandes asynchrones
Dans les applications Web qui voient un grand nombre de demandes simultanées au démarrage ou ont une charge en rafale (où la concurrence augmente soudainement), rendre ces appels de service Web asynchrones augmentera la réactivité de votre application. Une demande asynchrone prend le même temps à traiter qu'une demande synchrone. Par exemple, si une demande effectue un appel de service Web qui nécessite deux secondes pour se terminer, la demande prend deux secondes, qu'elle soit effectuée de manière synchrone ou asynchrone . Toutefois, lors d'un appel asynchrone, un thread n'est pas bloqué de répondre à d'autres demandes pendant qu'il attend la fin de la première demande. Par conséquent, les demandes asynchrones empêchent la mise en file d'attente des demandes et la croissance du pool de threads lorsqu'il existe de nombreuses demandes simultanées qui appellent des opérations de longue durée.
pour les mots en gras, je ne pouvais pas les comprendre comment une demande asynchrone prend le même temps à traiter qu'une demande synchrone?
Par exemple:
public async Task MyMethod()
{
Task<int> longRunningTask = LongRunningOperation();
//indeed you can do independent to the int result work here
//and now we call await on the task
int result = await longRunningTask;
//use the result
Console.WriteLine(result);
}
public async Task<int> LongRunningOperation() // assume we return an int from this long running operation
{
await Task.Delay(1000); //1 seconds delay
return 1;
}
Ce que je comprends que LongRunningOperation()
démarre l'exécution à partir de la première ligne appelant ici Task<int> longRunningTask = LongRunningOperation();
et retourne une valeur une fois appelé await
, donc de mon point de vue, le code asynchrone est plus rapide que synchrone, Est-ce correct?
Ce que je comprends, c'est que le thread principal travaillant sur l'exécution de MyMethod()
n'est pas bloqué en attendant que LongRunningOperation()
soit accompli mais il retourne au pool de threads pour servir une autre requête. y a-t-il donc un autre thread assigné à LongRunningOperation();
pour l'exécuter?
Si oui alors quelle est la différence entre la programmation asynchrone et la programmation multithreading?
Mise à jour:
disons que le code devient comme ça:
public async Task MyMethod()
{
Task<int> longRunningTask = LongRunningOperation();
//indeed you can do independent to the int result work here
DoIndependentWork();
//and now we call await on the task
int result = await longRunningTask;
//use the result
Console.WriteLine(result);
}
public async Task<int> LongRunningOperation() // assume we return an int from this long running operation
{
DoSomeWorkNeedsExecution();
await Task.Delay(1000); //1 seconds delay
return 1;
}
Dans ce cas, LongRunningOperation()
sera-t-elle exécutée par un autre thread pendant l'exécution de DoIndependentWork()
?
Les opérations asynchrones ne sont pas plus rapides. Si vous attendez 10 secondes de manière asynchrone (ie await Task.Delay(10000)
) ou synchrone (ie Thread.Sleep(10000)
) cela prendrait les mêmes 10 secondes . La seule différence serait que le premier ne maintiendrait pas un thread en attente mais le second le ferait .
Maintenant, si vous lancez une tâche et n'attendez pas qu'elle se termine immédiatement, vous pouvez utiliser le même thread pour effectuer un autre travail, mais cela n'accélère pas l'exécution de l'opération asynchrone:
var task = Task.Delay(10000);
// processing
await task; // will complete only after 10 seconds
À propos de votre deuxième question: Task.Delay
(comme les autres opérations vraiment asynchrones) n'a pas besoin d'un thread pour être exécuté et donc il n'y a pas de thread . Task.Delay
est implémenté à l'aide d'un System.Threading.Timer
que vous lancez et déclenche un événement quand c'est fait, en attendant il n'a pas besoin d'un thread car il n'y a pas de code à exécuter.
Ainsi, lorsque le thread qui exécutait MyMethod
atteint le await longRunningTask
il est libéré (tant que longRunningTask
n'est pas encore terminé). S'il s'agissait d'un thread ThreadPool
, il reviendra au ThreadPool
où il pourra traiter un autre code dans votre application.
Concernant la mise à jour, le flux serait le suivant:
MyMethod
commence le traitementLongRunningOperation
commence le traitementDoSomeWorkNeedsExecution
est exécuté sur le thread appelantawait
est atteint dans LongRunningOperation
et donc une tâche chaude est retournée.DoIndependentWork
est exécuté par le même thread appelant (LongRunningOperation
est toujours "en cours d'exécution", aucun thread n'est nécessaire)await
est atteint dans MyMethod
. Si la tâche d'origine est terminée, le même thread se poursuivra de manière synchrone, sinon une tâche chaude sera renvoyée et se terminera éventuellement.Donc, le fait que vous utilisez async-await
vous permet d'utiliser un thread qui serait sinon bloqué en attendant de manière synchrone un travail gourmand en CPU.
Considérez la différence entre:
Thread.Sleep(1000);
et
await Task.Delay(1000);
les deux prendront une seconde pour courir. Cependant, dans le premier cas, le thread actuel sera bloqué (et toutes ses ressources inutiles) tandis que dans le dernier cas, le thread actuel peut faire autre chose qui est utile (par exemple, servir une autre demande).
L'asynchronicité ne consiste pas à accélérer des séquences d'instructions individuelles, mais à être capable de faire des choses lorsque le code synchrone se bloque.
Ré. ne autre question
Le ou les threads libérés seront utilisés pour d'autres choses; aucun thread ne sera affecté jusqu'à la fin de l'opération. Cela est possible car le système d'exploitation sous-jacent est lui-même asynchrone. Dans l'exemple ci-dessus, une minuterie est utilisée qui est signalée pour un thread à ramasser lorsqu'un thread est libre, plutôt qu'un thread arrêté pour un interne.
(en s'appuyant sur la réponse d'I3arnon)
Il n'est pas absolument vrai que les opérations synchrones et les opérations utilisant async-await
prendra globalement le même temps.
Il y a une logique supplémentaire impliquée dans async-await
. Des vérifications des serveurs terminés et d'une machine d'état sont impliquées. Ainsi, certaines opérations asynchrones prennent plus de temps que l'opération synchrone correspondante.
D'un autre côté, la plupart des opérations adaptées à async-await
sont naturellement asynchrones et un traitement supplémentaire est nécessaire pour le rendre synchrone. Dans ces cas, l'opération asynchrone prend moins de temps que l'homologue synchrone.
Le devis sur la question concerne les applications Web. Pour les applications Web, les opérations asynchrones consistent davantage à traiter le nombre maximal de demandes dans un délai acceptable qu'à économiser quelques microsecondes de chaque demande. D'un autre côté, si un changement de contexte est impliqué, cela finit par prendre plus de temps et c'est pourquoi utiliser Task.Run
dans une application Web fait plus de mal que de bien à l'application.
Si vous souhaitez en savoir plus sur async-awit
, lisez les articles sur mon async-awit
curation .