Pour un apprentissage plus rapide ..
Comprendre le flux d'exécution de la méthode (avec un diagramme): 3 minutes
Introspection de la question (pour apprendre): 1 min
Passez rapidement à travers le sucre de syntaxe: 5 minutes
Partagez la confusion d'un développeur: 5 minutes
Problème: changez rapidement une implémentation réelle du code normal en code asynchrone: 2 minutes
Où ensuite?
Comprendre le flux d'exécution de la méthode (avec un diagramme): 3 minutes
Dans cette image, concentrez-vous sur # 6 (rien de plus)
À l'étape n ° 6: l'exécution s'est arrêtée ici car elle est à court de travail. Pour continuer, il a besoin d'un résultat de getStringTask (sorte de fonction). Par conséquent, il utilise un await
opérateur pour suspendre sa progression et rendre le contrôle (rendement) à l'appelant (de cette méthode dans laquelle nous sommes). L'appel réel à getStringTask a été effectué plus tôt dans # 2. Au n ° 2, une promesse a été faite de renvoyer un résultat de chaîne. Mais quand rendra-t-il le résultat? Devrions-nous (# 1: AccessTheWebAsync) refaire un deuxième appel? Qui obtient le résultat, # 2 (instruction d'appel) ou # 6 (instruction en attente)
L'appelant externe d'AccessTheWebAsync () attend également maintenant. Ainsi, l'appelant attend AccessTheWebAsync et AccessTheWebAsync attend GetStringAsync pour le moment. La chose intéressante est AccessTheWebAsync a fait un peu de travail avant d'attendre (# 4) peut-être pour gagner du temps. La même liberté de multitâche est également disponible pour l'appelant externe (et tous les appelants de la chaîne) et c'est le plus grand plus de ce truc 'async'! Vous avez l'impression que c'est synchrone ... ou normal mais ce n'est pas le cas.
Rappelez-vous, la méthode a déjà été retournée (# 2), elle ne peut pas revenir à nouveau (pas de deuxième fois). Alors, comment l'appelant saura-t-il? Il s'agit de tâches! La tâche a été réussie. La tâche était attendue (pas la méthode, pas la valeur). La valeur sera définie dans la tâche. Le statut de la tâche sera défini pour se terminer. L'appelant surveille simplement la tâche (# 6). Donc 6 # est la réponse à l'endroit où / qui obtient le résultat. Lectures supplémentaires pour plus tard ici .
Questionner l'introspection pour apprendre le plaisir: 1 min
Ajustons un peu la question:
Comment et quand utiliser et ? async
await
Tasks
Parce que l'apprentissage Task
couvre automatiquement les deux autres (et répond à votre question)
Passez rapidement à travers le sucre de syntaxe: 5 minutes
Avant la conversion (méthode originale)
internal static int Method(int arg0, int arg1)
{
int result = arg0 + arg1;
IO(); // Do some long running IO.
return result;
}
une méthode Task-ified pour appeler la méthode ci-dessus
internal static Task<int> MethodTask(int arg0, int arg1)
{
Task<int> task = new Task<int>(() => Method(arg0, arg1));
task.Start(); // Hot task (started task) should always be returned.
return task;
}
Avons-nous mentionné attendre ou async? Non. Appelez la méthode ci-dessus et vous obtenez une tâche que vous pouvez surveiller. Vous savez déjà ce que la tâche renvoie .. un entier.
L'appel d'une tâche est légèrement délicat et c'est à ce moment que les mots clés commencent à apparaître. Appelons MethodTask ()
internal static async Task<int> MethodAsync(int arg0, int arg1)
{
int result = await HelperMethods.MethodTask(arg0, arg1);
return result;
}
Même code ci-dessus ajouté comme image ci-dessous:
- Nous attendons que la tâche soit terminée. D'où le
await
- Puisque nous utilisons wait, nous devons utiliser
async
(syntaxe obligatoire)
- MethodAsync avec
Async
comme préfixe (norme de codage)
await
est facile à comprendre mais les deux ( async
, Async
) restants peuvent ne pas l'être :). Eh bien, il faut faire beaucoup plus de sens au compilateur though.Further lit pour plus tard ici
Il y a donc 2 parties.
- Créer une «tâche»
- Créer du sucre syntaxique pour appeler la tâche (
await+async
)
Rappelez-vous, nous avons eu un appelant externe à AccessTheWebAsync () et cet appelant n'est pas épargné non plus ... c'est-à-dire qu'il a également besoin du même await+async
. Et la chaîne continue. Mais il y aura toujours un Task
à une extrémité.
Tout va bien, mais un développeur a été surpris de voir # 1 (tâche) manquant ...
Partagez la confusion d'un développeur: 5 minutes
Un développeur a fait une erreur de ne pas implémenter Task
mais cela fonctionne toujours! Essayez de comprendre la question et juste la réponse acceptée fournie ici . J'espère que vous avez lu et bien compris. Le résumé est que nous ne pouvons pas voir / implémenter 'Task' mais il est implémenté quelque part dans une classe parent. De même, dans notre exemple, appeler un déjà construit MethodAsync()
est beaucoup plus facile que d'implémenter cette méthode avec un Task
( MethodTask()
) nous-mêmes. La plupart des développeurs ont du mal à se repérer Tasks
lors de la conversion d'un code en code asynchrone.
Conseil: essayez de trouver une implémentation Async existante (comme MethodAsync
ou ToListAsync
) pour sous-traiter la difficulté. Nous avons donc seulement besoin de traiter avec Async et d'attendre (ce qui est facile et assez similaire au code normal)
Problème: changez rapidement une implémentation réelle du code normal en fonctionnement asynchrone: 2 minutes
La ligne de code indiquée ci-dessous dans Data Layer a commencé à se rompre (à de nombreux endroits). Parce que nous avons mis à jour une partie de notre code du framework .Net 4.2. * Vers le core .Net. Nous avons dû résoudre ce problème en 1 heure partout dans l'application!
var myContract = query.Where(c => c.ContractID == _contractID).First();
peasy facile!
- Nous avons installé le package de nuget EntityFramework car il contient QueryableExtensions. Ou en d'autres termes, il fait l'implémentation Async (tâche), afin que nous puissions survivre avec du code simple
Async
et await
.
- namespace = Microsoft.EntityFrameworkCore
la ligne de code d'appel a changé comme ça
var myContract = await query.Where(c => c.ContractID == _contractID).FirstAsync();
La signature de la méthode est passée de
Contract GetContract(int contractnumber)
à
async Task<Contract> GetContractAsync(int contractnumber)
la méthode d'appel a également été affectée: a GetContractAsync(123456);
été appelée en tant queGetContractAsync(123456).Result;
Nous l'avons changé partout en 30 minutes!
Mais l'architecte nous a dit de ne pas utiliser la bibliothèque EntityFramework juste pour ça! Oops! drame! Ensuite, nous avons fait une implémentation de tâche personnalisée (yuk). Que vous savez comment. Toujours facile! ..encore yuk ..
Où ensuite?
Il y a une merveilleuse vidéo rapide que nous pourrions regarder sur la conversion des appels synchrones en asynchrones dans ASP.Net Core , c'est peut-être probablement la direction que l'on prendrait après avoir lu ceci.