async + attendre == synchronisation?

24

Je suis tombé sur ce post qui parle de faire des requêtes Web asynchrones.

Maintenant, la simplicité mise à part, si dans le monde réel, tout ce que vous faites est de faire une demande asynchrone et de l'attendre à la ligne suivante, n'est-ce pas la même chose que de faire un appel de synchronisation en premier lieu?

Mrchief
la source
5
Pas exactement. Votre code est synchrone dans le sens où rien ne se produit jusqu'à ce que vous obteniez un résultat. Cependant, en dessous, vous avez probablement abandonné le thread sur lequel vous exécutiez jusqu'à ce que la méthode async revienne, puis vous avez été affecté à un autre thread pour continuer à exécuter.
R0MANARMY
2
c'est mais avec async vous pouvez faire une autre async en même temps et ensuite attendre le 2, avec la synchronisation ce n'est pas possible
ratchet freak
Voici un article ( tomasp.net/blog/async-compilation-internals.aspx ) discutant de certains des sous-le capot de l'async en C # - il fait partie d'une série couvrant la programmation asynchrone en C # et F #.
paul
@ratchetfreak: Oui, cela va de soi si vous effectuez plusieurs appels.
Mrchief
@ R0MANARMY: Si votre application fait autre chose, alors oui et async + wait permet cela. Akim le dit le mieux! Mais imaginez que le code ne soit pas dans le gestionnaire button_click, ou tout autre gestionnaire d'événements pour cette question. Si quelqu'un copie aveuglément le code (asynchrone + lignes d'attente), dans n'importe quelle méthode, cela peut donner une fausse impression que votre code est asynchrone, mais en fait peut-être pas.
Mrchief

Réponses:

32

Non, à async + await != synccause de la continuation

De MSDN «Programmation asynchrone avec Async et Await (C # et Visual Basic)»

Les méthodes asynchrones sont destinées à être des opérations non bloquantes. Une expression d'attente dans une méthode async ne bloque pas le thread en cours pendant l'exécution de la tâche attendue. Au lieu de cela, l'expression signe le reste de la méthode en tant que continuation et renvoie le contrôle à l'appelant de la méthode async .

Par exemple, l'exécution asynchrone ne bloquera pas le thread d'interface utilisateur et Some TextBox.Textsera mise à jour une fois le téléchargement terminé

private async void OnButtonClick()
{
   SomeTextBox.Text = await new WebClient().DownloadStringTaskAsync("http://stackoverflow.com/");
}
Akim
la source
Très gentiment dit!
Mrchief
Pourriez-vous expliquer plus en détail. Êtes-vous en train de dire ... que sans cela ... vous ne seriez pas en mesure d'interagir avec l'interface utilisateur ... car ce serait sur le thread principal. Cela signifie donc que cela ne devient applicable que dans un programme de type application apposé sur le Web où l'interaction est distincte du thread du serveur Web. Donc, dans une coquille de noix, cela ne devient important, c'est-à-dire pas de synchronisation * lorsque votre thread principal est le thread en cours d'exécution. Cela ne créerait-il pas un comportement inattendu, c'est-à-dire que dans une application (1 thread principal), deux boutons ont été cliqués ... mais vous devriez pouvoir cliquer sur le 1 sans terminer le premier?
Seabizkit
Et alors Console.WriteLine(await GetStringOverNetwork());? Que faire si vous avez besoin de la sortie de l'appel asynchrone? Le programme se bloquerait-il au premier accès, même si le thread pouvait potentiellement continuer son exécution?
Andrew
6

Non ce n'est pas pareil.

Votre asyncbloc de code attend que l' awaitappel revienne pour continuer, mais le reste de votre application n'attend pas et peut continuer comme d'habitude.

En revanche, un appel synchrone ferait attendre toute votre application ou thread jusqu'à ce que le code ait fini de s'exécuter pour continuer avec autre chose.

Rachel
la source
l'appel de synchronisation n'a-t-il pas pu être implémenté car async + attend?
monstre à cliquet
@ratchetfreak Je pense que la configuration de wait / async entraîne des frais supplémentaires, donc je ne pense pas que vous souhaitiez coder l'intégralité de votre application avec. Je l'utilise uniquement pour exécuter des blocs de code potentiellement longs afin de ne pas verrouiller mes applications. :)
Rachel
5

S'il vous plaît permettez-moi de clarifier les choses en ce qui concerne async / wait.

Lorsque l'attente est rencontrée, la machine d'état sous-jacente permet au contrôle d'être retourné immédiatement. Ensuite, lorsque l'appel attendu est terminé, la machine d'état sous-jacente permet à l'exécution de reprendre sur la ligne après l'appel attendu.

Par conséquent, le bloc asynchrone n'est pas bloqué et n'attend pas la fin de l'appel attendu; Le contrôle est renvoyé immédiatement lorsque la commande d'attente est rencontrée.

La machine d'état sous-jacente fait partie de la "magie" derrière l'utilisation de l'async / wait qui n'est pas désaffectée et manquée.

Cedric Harris
la source
2

Je suis tombé dessus avec la même question à l'esprit, mais après avoir lu les réponses, la question semble persister, confuse par les références à la «magie sous le capot».

De la programmation asynchrone mentionnée ci-dessus :

  • Le asyncmot clé transforme une méthode en méthode asynchrone, ce qui vous permet d'utiliser leawait mot clé dans son corps.
  • Quand le await mot clé est appliqué, il suspend la méthode d'appel et rend le contrôle à son appelant jusqu'à la fin de la tâche attendue.
  • awaitne peut être utilisé qu'à l'intérieur d'une asyncméthode.

Le contexte rencontré awaitest-il bloqué?

  • Oui . Il s'agit essentiellement d'une barrière de synchronisation locale pour maintenir un état connu dans le contexte de l'exécution; sauf que d'autres contextes, le cas échéant, ne sont pas joints.

Le reste de l'application se bloque-t-il sur le await?

  • Cela dépend de la façon dont votre candidature est rédigée. S'il s'agit d'une série de awaittâches ed dépendantes lancées séquentiellement dans le même contexte (voir: Essayer de comprendre un comportement asynchrone / attendre )

    await asyncCall1();
    await asyncCall2();  // waits for asyncCall1() to complete

    de cette façon chacun await bloquerait le frai du suivant.

    En revanche, les mêmes tâches dépendantes lancées en parallèle s'exécuteraient en parallèle et le contexte ne se bloquerait qu'au resp. await:

    Task<int> t1 = asyncCall1();
    Task<string> t2 = asyncCall2();  // runs in parallel with asyncCall1()
    int val = await t1;
    string str = await t2;  // waits for asyncCall1() to complete

    En général, l' awaitexécution renvoie au contexte externe, d'où le contexte actuel est appelé. Cependant, si le contexte extérieur lui-même attend le courant, c'est comme un awaits séquentiel dans le même contexte.

Donc, pour récolter les asyncbénéfices, il faut concevoir l'application pour exécuter plusieurs contextes parallèles (interface utilisateur, client de données, etc.), puis awaitdans un contexte, elle s'exécute dans d'autres contextes, afin que l'application entière ne bloque pas un individu await.

trop synchronisé
la source