Je voudrais poser une question simple sur le code ci-dessous: Cet exemple exécute les fonctions de calcul de manière synchrone. Quand la ligne "// attend la tâche.delay (1);" Sera valide, les fonctions de calcul seront exécutées de manière parallèle. P> La question est la suivante: pourquoi, en ajoutant simple attendre, la fonction calc est alors asynchrone?
Je sais à propos des exigences de paire Async / Awai. Je demande ce qu'il se passe vraiment lorsque le délai d'attente simple est ajouté au début d'une fonction. La fonction de calcul entière est ensuite reconnue pour être exécutée dans un autre thread, mais pourquoi? P> Lorsque j'ai ajouté un fil de lecture au code: static async Task<int> Calc(int a)
{
await Task.Delay(1);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
int result = 0;
for (int k = 0; k < a; ++k)
{
for (int l = 0; l < a; ++l)
{
result += l;
}
}
return result;
}
4 Réponses :
Une fonction ASYNC renvoie la tâche incomplète à l'appelant à son premier sans le attendre code>. Après cela, le
attendre code> du côté appelant attendra cette tâche à devenir complète. P>
attendre la tâche.delay (1) code>,
calc () code> n'a aucun attente de son propre, de sorte que ne reviendra que à l'appelant quand il s'exécute à la fin. A ce stade, la tâche
renvoyée code> est déjà terminée, le
attendre code> sur le site d'appel utilise immédiatement le résultat sans invoquer la machine ASYNC. P>
En utilisant un motif asynchronisé / attendre, vous avez l'intention de votre méthode Nous devons établir que les tâches sont généralement < EM> asynchrones em> dans leur nature, mais pas parallèle em> - le parallélisme est une caractéristique de threads. Cependant, sous la hotte, Certains em> seront utilisés pour exécuter vos tâches sur. Selon le contexte, vous exécutez votre code dans, plusieurs tâches peuvent être exécutées ou non en parallèle ou de manière séquentielle - mais elles seront (autorisées) asynchrones. P> Un bon moyen d'internaliser cela est décrit une enseignant (the thread) répondant à la question (les tâches) en classe. Un enseignant ne sera jamais en mesure de répondre à deux questions différentes simultanément - c'est-à-dire en parallèle - mais elle sera en mesure de répondre aux questions de plusieurs étudiants et peut également être interrompue avec de nouvelles questions entre les deux. P> Spécifiquement, async / attendre est une fonctionnalité de multirofesseur coopérative (accent sur la "coopérative") où les tâches ne doivent être programmées que sur un thread si ce fil est libre - et si une tâche est déjà exécutée sur ce fil, il doit céder manuellement la place. . (Que ce soit et combien de threads sont disponibles pour l'exécution dépendent de l'environnement que votre code est exécuté.) P> lors de l'exécution En règle générale, chaque fois que vous dans votre exemple, les rendements code> Calc code> en raison de la tâche dans une autre note: chaque fois que vous souhaitez exécuter un code synchrone de manière asynchrone, utilisez calc code> pour exécuter en tant que tâche:
Task.Delay (1) Code> Le code annonce qu'il s'agit de dormir, quels signaux à la Planificateur qu'une autre tâche peut exécuter, permettant ainsi une asynchronicité. La façon dont il est utilisé dans votre code, c'est, en substance, une version légèrement pire de
Tâche.yield code>
(vous pouvez trouver plus de détails à ce sujet dans les commentaires ci-dessous). P> Await Code>, la méthode actuellement exécutée est "retournée" de, marquant le code après une continuation. Cette suite ne sera exécutée que lorsque le planificateur de tâche sélectionne à nouveau la tâche actuelle de l'exécution. Cela peut arriver si aucune autre tâche n'exécute actuellement et n'attend que d'être exécutée - par ex. Parce qu'ils ont tous cédé ou
attendre code> quelque chose "longueur longue". p>
en raison de la tâche
. Délai code> et l'exécution retourne à la méthode code> principale code>. Cela pénètre à son tour dans la méthode suivante
Calc code> et le modèle se répète. Comme il a été établi dans d'autres réponses, ces continuations peuvent ou non exécuter sur différents threads, en fonction de l'environnement - sans contexte de synchronisation (par exemple dans une application de console), il peut em> arriver. Pour être clair, ce n'est ni une caractéristique de la tâche
.delay code> ni async / attendre, mais de la configuration de votre code s'exécute dans. Si vous Exigez em> le parallélisme, utilisez des threads appropriés ou Assurez-vous que vos tâches sont lancées de telle sorte qu'elles encouragent l'utilisation de threads multiples. P>
tâche.run () code>
pour l'exécuter. Cela s'assurera que cela ne vous empêche pas trop en utilisant toujours un fil de fond. Cela répond donc sur longRunning code> Les tâches peuvent être perspicaces. p> p>
Async / attendre n'est pas concerné par les threads et n'a rien à voir avec la planification de la coopération et du fil de la coopérative. S'il vous plaît voir Stackoverflow.com/q/17661428/11683 ou blog.stephancleary.com/2013/11/Ille-is-no-ththread.html .
Chaque tâche est exécutée sur un fil. Ces threads sont gérés par le planificateur de tâches.
Je ne suis pas sûr de savoir pourquoi cela a été marqué ... Je suis plongé ... bien que un peu technique, ce ne soit pas faux.
@Seabizkit Il a été voté parce que c'est très faux. Async / attendre ne concerne pas les threads et dire que c'est très trompeur. L'OP a une application de console qui n'a pas de contexte de synchronisation, de sorte que les tâches n'auraient aucune obligation de fonctionner sur le même thread. Ils peuvent donc très facilement se retrouver sur différents threads, un pour chaque A code>, < Code> B code> et
C code>, qui déprime déjà la partie "si ce fil est libre" portion, car il est i> un fil disponible à chaque fois, mais il n'est pas utilisé .
@Seabizkit Si le même code a été exécuté dans une application WinForms, où le contexte de synchronisation est lié au thread d'interface utilisateur, alors a code>,
b code> et
c code > Est-ce que tous couriraient sur le même fil, mais ils seraient tous en vol simultanément, pas en ordre de l'achèvement, ce qui l'évite de l'autre côté: il n'est pas i> un fil disponible, mais tous les trois Les tâches sont démarrées simultanément.
@Gserg Quel que soit le thread est utilisé, il doit être gratuit pour qu'une tâche soit programmée. Qu'il s'agisse ou non de multiples threads disponibles est une question totalement différente, comme ce que le thread est utilisé pour exécuter une continuation. Si cela ne serait pas sur les threads, alors exécutez thread.sleep (int32.maxvalue) code> dans une tâche serait une chose parfaitement sensée à faire ... et pourtant ce n'est pas le cas.
La tâche .Delay (1) code> peut être configurée pour capturer le contexte de synchronisation actuel ou non. La tâche
.yield code> n'est pas configurable. Il capture toujours le contexte. C'est une raison pour laquelle ces deux ne sont pas équivalents. L'autre des raisons est que la tâche
.yield code> quand attendu va toujours répondre à
IsCompleted code>
avec false code>. Ceci n'est pas garanti pour
Task.Delay (1) code>, et l'attente de cela pourrait être une opération synchrone (potentiellement).
Je pense que la réponse pourrait être améliorée en mentionnant que le comportement serait différent s'il est exécuté sur un fil de l'interface utilisateur.
Tout ce qui se passe est faux. "Les tâches sont asynchrones dans leur nature" calc code> n'est pas i> asynchrone. Il devrait être clairement, mais parce que cela a été mis en œuvre de manière incorrecte, ce n'est pas le cas. "Mais pas parallèle" si c'est étaient i> asynchrones, ce que l'OP va le courir en parallèle, quels que soient ses internes. "Certains threads seront utilisés pour exécuter vos tâches sur" Non, de nombreuses tâches représentent le travail pas fait par n'importe quel fil du tout i>. C'est juste (espérons-le) asynchrone, d'une manière ou d'une autre.
"Selon le contexte, vous exécutez votre code dans, plusieurs tâches peuvent être exécutées ou non en parallèle ou de manière séquentielle" uniquement si ces méthodes sont en train de programmer sur le contexte de synchronisation actuel. Ils ne devraient faire que cela pour le travail qui ne fonctionne pas longtemps. "Async / attendre est une caractéristique de multipérapage coopérative (accent sur" Coopérative ") où les tâches ne doivent être programmées que sur un thread". Les tâches sont une représentation des travaux effectués à l'avenir, et non un mécanisme de planification des travaux sur les threads. La planification des travaux sur les threads est distincte et non inhérente aux tâches.
"Lors de l'exécution de la tâche.Delay (1), le code annonce qu'il souhaite dormir" Non, fonctionnant qui produit une tâche qui sera complète dans un milliseconde. Il ne fait rien à l'exécution de la méthode actuelle du tout. "Notez que chaque fois que vous attendez, la méthode actuellement exécutée est" retournée "de" Non, c'est le premier attendre d'une tâche qui n'est pas déjà complète.
"Cette suite ne sera exécutée que lorsque le planificateur de tâches sélectionne la tâche actuelle d'exécution" si i> vous configurez l'attente pour utiliser le contexte de synchronisation actuel et s'il y en a un, la suite est planifiée sur ce contexte. Ce n'est pas la même chose que ce que vous avez dit.
la version de layman ...
Rien dans le processus ne donne que le temps de processeur de processeur @sunside dit le la même chose juste plus techniquement. p> vs p> la raison pour laquelle il ressemble à sa "manière parallèle" est que Il suffit de donner aux autres tâches des tâches du processeur. p> exemple; aka sans délai p> exemple 2; alias avec délai p> Ce que vous devriez trouver est bien que davantage démarré plus tôt, l'heure globale sera plus longue que celle-ci de sauter entre tâches sans avantage avec une tâche asynchrone façonnée. où comme, si l'attente de la tâche.delay (1) était une vraie fonction asynchrone aka dans la nature asynchrone, la prestation serait que cela peut démarrer l'autre travail à l'aide du fil qui serait bloqué ... pendant qu'il attend quelque chose qui ne nécessite pas le thread. p>
L'exemple classique de travail d'E / S fait des demandes Web. L'écriture sur le disque n'est pas réellement pure d'E / S, en raison de la mise en œuvre des API asynchrones connexes (elles sont implémentées Mauvaise ).
@Theodorzoulias à 100% mais l'idée est là .... Fondamentalement quelque chose qui n'est pas limité par le fil actuel. Comme je l'ai dit, j'essayais de tomber en panne .. comme certains marquaient la touche Solean Soled Down ... ce qui n'a aucun sens pour moi. Je pense qu'il y avait une idée de la compréhension. Je comprends ... je ne pose pas la question ... J'essaie simplement de donner un exemple simple et non super spécifique .. pour allonger la fondation ... du point Solefide était allongé ... j'essayais de souligner que Sans Tâche.Delay (1); code> Vous écrivez simplement une opération synchrone car elle est synchrone dans la nature, qui ...
N'aurait changé que d'avoir plus de sens si vous aviez un exemple d'opération qui soutient l'asynchrone de nature. Aka on pourrait écrire sur le disque ou lire à partir du disque. Il y en a beaucoup mais essayait de se rapporter à celui que PPL peut se rapporter à ..
@Theodorzoulias en.wikipedia.org/wiki/input/output
@Seabizkit En fait, l'heure globale avec des tâches asynchrones trutées (attendre la tâche.delay (1)) est 3 fois plus courte. C'est la raison pour laquelle j'ai utilisé une phrase parallèle, car l'observation du temps, me donner la conclusion que tous les codes après attendre la tâche. Delay, a été réalisée dans différents threads. Je ne sais pas si j'ai raison dans cette conclusion?
@ user1885750 Je viens d'écrire un test ... ce qui le prouve son plus lent .... Donc, je suppose que tout dépend de la manière dont vous écrivez le code que vous utilisez pour tester, si vous testez le code, le test est défectueux. Ill ajouter le code de test i pour vérifier ... Ce n'est pas et une science exacte et vous devez utiliser des outils de marquage de banc réels, mais même dans ce test de brut, vous pouvez voir sa plus lente.
@Seabizkit Mais il y a une énorme différence dans votre code par rapport à mon. Votre code: Tâche
@ user1885750 Je voyais aussi ce que vous étiez ... mais je sais mieux en termes de tester et de ce que le code fait en réalité, je sais que ce sera plus lent (dans ce cas) ... mais pour aider avec Ceci .. vous devez utiliser Google "Le mode de publication de débogage VS dans .NET pour la performance" qui vous mènera à .. Github .com / dotnet / Benchmarkdototnet .
@Seabizkit Je ne sais pas ce que vous voulez dire exactement. Pensez-vous que j'ai mesuré le code dans le mauvais sens? Ce n'est pas une science de la fusée. Il suffit d'utiliser mon code (pas le vôtre) et de le mesurer. J'ai obtenu 0,5S sans délai et 0,28 avec délai (console, noyau .NET, version). Je ne sais pas pourquoi tu as obtenu les résultats opposés. Peut-être que quelqu'un d'autre testera le code aussi.
Les miens et les urs sont la même chose fondamentalement ... simplement raccourci la longueur de lecture et couru plusieurs fois ... N'utilisez jamais les premiers résultats ... (Ceci s'appelle l'échauffement ou le démarrage à froid) de toute façon que vous vouliez prendre la moyenne. .., vous travaillez avec une telle petite à ce sujet .. que c'est fondamentalement un-mesurable ..Run le même test multiple plusieurs fois. Non ... Exécutez le même code ... Plusieurs fois pas du début froid. En mode de libération ... et vous verrez que chaque fois si plus de 100 appels le seul sans le retard gagnera. La faction de la durée de la CPU que vous essayez de mesurer est très très
ps ce lien est or docs.microsoft.com/en-us/archive/blogs/benwilli/...
@Sabizkit mais c'est évident. Je vous donne le temps moyen de nombreuses mesures. Je mettez en œuvre des algorithmes pendant de nombreuses années et j'ai une expérience sur les mesures de temps. J'ai mesuré le temps d'exécution plusieurs fois dans une période de programme. J'ai également mesuré un autre problème / algorithmes en utilisant le même scénario (avec des tâches d'arborescence et en attente de retard). De plus, j'ai mesuré ce problème en dehors de Visual Studio et j'ai toujours des résultats similaires. Peut-être que c'est à cause de la demande de console.
Il est important de comprendre comment Premièrement, ils commencent à fonctionner de manière synchrone, sur le même thread, tout comme chaque méthode. Sans que La magie se produit au premier donc lorsque vous avez Comment La poursuite de Toutefois, car il s'agit d'une application de console, qui n'a pas de contexte de synchronisation, les continuations se produisent sur tout thread threadpool dès que le Vaut également la peine de noter: commençant par C # 7.1, vous pouvez faire votre async code> méthodes fonctionne.
attendre la tâche.Delay (1) code> ligne, le compilateur vous avera averti que la méthode serait complètement synchrone. Le mot clé code> async code> ne fait fonctionner que votre méthode asynchrone. Il suffit d'utiliser
attendre code>. P>
attendre code> qui agit sur une tâche
incomplète code>. À ce stade, la méthode retourne em>. Il renvoie une tâche
code> que vous pouvez utiliser pour vérifier lorsque le reste de la méthode est terminé. P>
attendre la tâche.delay (1) code > là, la méthode revient à cette ligne, permettant à votre
MAINSTYNC code> de passer à la ligne suivante et de démarrer l'appel suivant sur
Calc code>. p>
calc code> exécute (tout après
attendre la tâche.delay (1) code>) dépend du cas de "contexte de synchronisation". Dans ASP.NET (NON COE) ou une application d'interface utilisateur, par exemple, le contexte de synchronisation contrôle la manière dont les continuations fonctionnent et qu'ils enlèveraient l'une après l'autre. Dans une application UI, ce serait sur le même fil que cela a commencé. Dans ASP.NET, il peut s'agir d'un fil différent, mais toujours l'un après l'autre. Donc, dans les deux cas, vous ne verriez aucun parallélisme. P>
Tâche code> à partir de
Task.Delay (1) code> est terminé. Cela signifie que chaque continuation peut se produire en parallèle. P>
MAIN / code> Méthode code> Async code>, éliminant le besoin de Votre
MAINSTOYNC CODE> Méthode: P>
static async Task Main(string[] args)
Ajouter
async code> à une déclaration de méthode ne le rend pas magiquement asynchrone, ni n'utilise de threads séparés. Sans le
attendre la tâche.Delay (1); code> Déclaration, votre méthode est synchrone à 100% et fonctionnera ainsi séquentiellement. Cependant, avec la tâche impliquée, vous impliquez maintenant le pool de threads pour exécuter la continuation (le code après le délai). De plus, lorsque le code dans une méthode
async code> atteint un
attendre une tâche code> lorsque la tâche n'est pas encore terminée, il mettra la file d'attente du reste de la méthode comme une continuation, puis de retourner , permettant à tous ces 3 appels de méthode pour commencer comme ça.
En ce qui concerne la modification, oui, dans une demande de console spécifiquement, les tâches s'exécuteront sur différents threads. Non, ce n'est pas la raison pour laquelle ils commencent tous simultanément. La raison est que avec
tâche.delay code>, l'exécution revient à
mainasync code> avant la fin de la tâche, et sans cela ne le fait pas, comme expliqué dansCette meilleure version de Ma réponse originale . Même se produirait si les tâches ne fonctionnaient pas sur des threads distincts.