Flux de contrôle dans les programmes Async (Visual Basic)
Vous pouvez écrire et tenir à jour des programmes asynchrones plus facilement à l’aide des mots clés Async
et Await
. Toutefois, les résultats peuvent vous étonner si vous ne comprenez pas le fonctionnement de votre programme. Cette rubrique suit le flux de contrôle par le biais d’un programme asynchrone simple pour vous montrer quand le contrôle se déplace d’une méthode à une autre et quelles informations sont transférées à chaque fois.
Notes
Les mots clés Async
et Await
ont été introduits dans Visual Studio 2012.
En général, vous marquez les méthodes qui contiennent du code asynchrone avec le modificateur Async. Dans une méthode marquée avec un modificateur async, vous pouvez utiliser un opérateur Await (Visual Basic) pour spécifier où la méthode s’interrompt afin d’attendre qu’un processus asynchrone appelé s’exécute. Pour plus d’informations, consultez Programmation asynchrone avec Async et Await (Visual Basic).
L’exemple suivant utilise des méthodes async pour télécharger le contenu d’un site web spécifié sous forme de chaîne et afficher la longueur de la chaîne. Il contient les deux méthodes suivantes.
startButton_Click
, qui appelleAccessTheWebAsync
et affiche le résultat.AccessTheWebAsync
, qui télécharge le contenu d’un site web sous forme de chaîne et retourne la longueur de la chaîne.AccessTheWebAsync
utilise une méthode asynchrone HttpClient, GetStringAsync(String), pour télécharger le contenu.
Des lignes numérotées apparaissent à des points stratégiques du programme pour vous aider à comprendre comment le programme s’exécute et expliquer ce qui se produit à chaque point marqué. Les lignes sont étiquetées de « ONE » à « SIX ». Les étiquettes représentent l’ordre dans lequel le programme atteint ces lignes de code.
Le code suivant illustre un plan du programme.
Class MainWindow
Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs) Handles StartButton.Click
' ONE
Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()
' FOUR
Dim contentLength As Integer = Await getLengthTask
' SIX
ResultsTextBox.Text &=
vbCrLf & $"Length of the downloaded string: {contentLength}." & vbCrLf
End Sub
Async Function AccessTheWebAsync() As Task(Of Integer)
' TWO
Dim client As HttpClient = New HttpClient()
Dim getStringTask As Task(Of String) =
client.GetStringAsync("https://learn.microsoft.com")
' THREE
Dim urlContents As String = Await getStringTask
' FIVE
Return urlContents.Length
End Function
End Class
Chacun des emplacements étiquetés de "ONE" à "SIX" affiche des informations sur l’état actuel du programme. La sortie suivante est produite :
ONE: Entering startButton_Click.
Calling AccessTheWebAsync.
TWO: Entering AccessTheWebAsync.
Calling HttpClient.GetStringAsync.
THREE: Back in AccessTheWebAsync.
Task getStringTask is started.
About to await getStringTask & return a Task<int> to startButton_Click.
FOUR: Back in startButton_Click.
Task getLengthTask is started.
About to await getLengthTask -- no caller to return to.
FIVE: Back in AccessTheWebAsync.
Task getStringTask is complete.
Processing the return statement.
Exiting from AccessTheWebAsync.
SIX: Back in startButton_Click.
Task getLengthTask is finished.
Result from AccessTheWebAsync is stored in contentLength.
About to display contentLength and exit.
Length of the downloaded string: 33946.
Configurer le programme
Vous pouvez télécharger le code que cette rubrique utilise à partir de MSDN, ou vous pouvez le créer vous-même.
Notes
Pour exécuter l’exemple, Visual Studio version 2012, ou une version ultérieure, et .NET Framework version 4.5, ou une version ultérieure, doivent être installés sur votre ordinateur.
Télécharger le programme
Vous pouvez télécharger l’application utilisée dans cette rubrique à partir de l’exemple Async : Flux de contrôle dans les programmes Async. Les étapes suivantes ouvrent et exécutent le programme.
Décompressez le fichier téléchargé, puis démarrez Visual Studio.
Dans la barre de menus, choisissez Fichier, Ouvrir, Projet/Solution.
Accédez au dossier qui contient l’exemple de code décompressé, ouvrez le fichier solution (.sln), puis choisissez la touche F5 pour générer et exécuter le projet.
Générer le programme vous-même
Le projet Windows Presentation Foundation (WPF) suivant contient l’exemple de code utilisé pour cette rubrique.
Pour exécuter le projet, procédez comme suit :
Démarrez Visual Studio.
Dans le menu principal, sélectionnez Fichier, Nouveau, Projet.
La boîte de dialogue Nouveau projet s’affiche.
Dans le volet Modèles installés, choisissez Visual Basic, puis Application WPF dans la liste des types de projets.
Entrez
AsyncTracer
comme nom du projet, puis choisissez le bouton OK.Le nouveau projet s’affiche dans l’Explorateur de solutions.
Dans l'éditeur de code Visual Studio, choisissez l'onglet MainWindow.xaml .
Si l’onglet n’est pas visible, ouvrez le menu contextuel de MainWindow.xaml dans l’Explorateur de solutions, puis choisissez Afficher le code.
Dans la vue XAML de MainWindow.xaml, remplacez le code par le code suivant.
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="MainWindow" Title="Control Flow Trace" Height="350" Width="525"> <Grid> <Button x:Name="StartButton" Content="Start" HorizontalAlignment="Left" Margin="221,10,0,0" VerticalAlignment="Top" Width="75"/> <TextBox x:Name="ResultsTextBox" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Bottom" Width="510" Height="265" FontFamily="Lucida Console" FontSize="10" VerticalScrollBarVisibility="Visible" d:LayoutOverrides="HorizontalMargin"/> </Grid> </Window>
Une fenêtre simple contenant une zone de texte et un bouton apparaît dans la vue Design de MainWindow.xaml.
Ajoutez une référence pour System.Net.Http.
Dans l’Explorateur de solutions, ouvrez le menu contextuel pour MainWindow.xaml.vb, puis choisissez Afficher le code.
Dans MainWindow.xaml.vb, remplacez le code par le code suivant.
' Add an Imports statement and a reference for System.Net.Http. Imports System.Net.Http Class MainWindow Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs) Handles StartButton.Click ' The display lines in the example lead you through the control shifts. ResultsTextBox.Text &= "ONE: Entering StartButton_Click." & vbCrLf & " Calling AccessTheWebAsync." & vbCrLf Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync() ResultsTextBox.Text &= vbCrLf & "FOUR: Back in StartButton_Click." & vbCrLf & " Task getLengthTask is started." & vbCrLf & " About to await getLengthTask -- no caller to return to." & vbCrLf Dim contentLength As Integer = Await getLengthTask ResultsTextBox.Text &= vbCrLf & "SIX: Back in StartButton_Click." & vbCrLf & " Task getLengthTask is finished." & vbCrLf & " Result from AccessTheWebAsync is stored in contentLength." & vbCrLf & " About to display contentLength and exit." & vbCrLf ResultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, contentLength) End Sub Async Function AccessTheWebAsync() As Task(Of Integer) ResultsTextBox.Text &= vbCrLf & "TWO: Entering AccessTheWebAsync." ' Declare an HttpClient object. Dim client As HttpClient = New HttpClient() ResultsTextBox.Text &= vbCrLf & " Calling HttpClient.GetStringAsync." & vbCrLf ' GetStringAsync returns a Task(Of String). Dim getStringTask As Task(Of String) = client.GetStringAsync("https://learn.microsoft.com") ResultsTextBox.Text &= vbCrLf & "THREE: Back in AccessTheWebAsync." & vbCrLf & " Task getStringTask is started." ' AccessTheWebAsync can continue to work until getStringTask is awaited. ResultsTextBox.Text &= vbCrLf & " About to await getStringTask & return a Task(Of Integer) to StartButton_Click." & vbCrLf ' Retrieve the website contents when task is complete. Dim urlContents As String = Await getStringTask ResultsTextBox.Text &= vbCrLf & "FIVE: Back in AccessTheWebAsync." & vbCrLf & " Task getStringTask is complete." & vbCrLf & " Processing the return statement." & vbCrLf & " Exiting from AccessTheWebAsync." & vbCrLf Return urlContents.Length End Function End Class
Appuyez sur la touche F5 pour exécuter le programme, puis choisissez le bouton Démarrer.
La sortie suivante doit s’afficher :
ONE: Entering startButton_Click. Calling AccessTheWebAsync. TWO: Entering AccessTheWebAsync. Calling HttpClient.GetStringAsync. THREE: Back in AccessTheWebAsync. Task getStringTask is started. About to await getStringTask & return a Task<int> to startButton_Click. FOUR: Back in startButton_Click. Task getLengthTask is started. About to await getLengthTask -- no caller to return to. FIVE: Back in AccessTheWebAsync. Task getStringTask is complete. Processing the return statement. Exiting from AccessTheWebAsync. SIX: Back in startButton_Click. Task getLengthTask is finished. Result from AccessTheWebAsync is stored in contentLength. About to display contentLength and exit. Length of the downloaded string: 33946.
Tracer le programme
Étapes UN et DEUX
Les deux premières lignes d’affichage suivent le chemin quand startButton_Click
appelle AccessTheWebAsync
et AccessTheWebAsync
appelle la méthode asynchrone HttpClientGetStringAsync(String). L’image suivante montre les appels de méthode à méthode.
Le type de retour de AccessTheWebAsync
et de client.GetStringAsync
est Task<TResult>. Pour AccessTheWebAsync
, TResult est un entier. Pour GetStringAsync
, TResult est une chaîne. Pour plus d’informations sur les types de retour de méthode asynchrone, consultez Types de retour Async (Visual Basic).
Une méthode async retournant une tâche retourne une instance de tâche quand le contrôle revient vers l’appelant. Le contrôle retourne d’une méthode async à son appelant quand un opérateur Await
est rencontré dans la méthode appelée ou quand la méthode appelée se termine. Les lignes qui sont étiquetées "THREE" à "SIX" suivent cette partie du processus.
Étape TROIS
Dans AccessTheWebAsync
, la méthode asynchrone GetStringAsync(String) est appelée pour télécharger le contenu de la page web cible. Le contrôle retourne de client.GetStringAsync
à AccessTheWebAsync
quand client.GetStringAsync
retourne une sortie.
La méthode client.GetStringAsync
retourne une tâche de la chaîne assignée à la variable getStringTask
dans AccessTheWebAsync
. La ligne suivante de l’exemple de programme illustre l’appel à client.GetStringAsync
et l’assignation.
Dim getStringTask As Task(Of String) = client.GetStringAsync("https://learn.microsoft.com")
Vous pouvez considérer la tâche comme une promesse faite par client.GetStringAsync
de produire au final une chaîne réelle. Pour le moment, si AccessTheWebAsync
a du travail à effectuer qui ne dépend pas de la chaîne promise de client.GetStringAsync
, ce travail peut se poursuivre pendant que client.GetStringAsync
attend. Dans l’exemple, les lignes de sortie suivantes, qui sont étiquetées « THREE », représentent la possibilité d’effectuer un travail indépendant
THREE: Back in AccessTheWebAsync.
Task getStringTask is started.
About to await getStringTask & return a Task<int> to startButton_Click.
L’instruction suivante interrompt la progression dans AccessTheWebAsync
quand getStringTask
est attendu.
Dim urlContents As String = Await getStringTask
L’illustration suivante montre le flux de contrôle entre client.GetStringAsync
et l’assignation à getStringTask
, puis entre la création de getStringTask
et l’application d’un opérateur await.
L’expression await suspend AccessTheWebAsync
jusqu’à ce que client.GetStringAsync
retourne une sortie. Dans le même temps, le contrôle retourne à l’appelant de AccessTheWebAsync
, startButton_Click
.
Notes
En général, vous attendez immédiatement l’appel à une méthode asynchrone. Par exemple, l’assignation suivante peut substituer le code précédent qui crée, puis attend getStringTask
: Dim urlContents As String = Await client.GetStringAsync("https://learn.microsoft.com")
Dans cette rubrique, l’opérateur await est appliqué ultérieurement pour s’adapter aux lignes de sortie qui marquent le flux de contrôle dans le programme.
Étape FOUR
Le type de retour déclaré de AccessTheWebAsync
est Task(Of Integer)
. Par conséquent, quand la méthode AccessTheWebAsync
est suspendue, elle retourne une tâche d’entier à startButton_Click
. Vous devez comprendre que la tâche retournée n’est pas getStringTask
. Il s’agit d’une tâche d’entier qui représente ce qu’il reste à effectuer dans la méthode interrompue, AccessTheWebAsync
. La tâche est une promesse de AccessTheWebAsync
de produire un entier quand la tâche est terminée.
L’instruction suivante assigne cette tâche à la variable getLengthTask
.
Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()
Comme dans AccessTheWebAsync
, startButton_Click
peut continuer le travail qui ne dépend pas des résultats de la tâche asynchrone (getLengthTask
) jusqu’à ce que la tâche soit attendue. Les lignes de sortie suivantes représentent ce travail :
FOUR: Back in startButton_Click.
Task getLengthTask is started.
About to await getLengthTask -- no caller to return to.
La progression dans startButton_Click
est suspendue quand getLengthTask
est attendu. L’instruction d’assignation suivante interrompt startButton_Click
jusqu’à ce que la méthode AccessTheWebAsync
soit terminée.
Dim contentLength As Integer = Await getLengthTask
Dans l’illustration suivante, les flèches indiquent le flux de contrôle entre l’expression await dans AccessTheWebAsync
et l’assignation d’une valeur à getLengthTask
, suivie du traitement normal dans startButton_Click
jusqu’à ce que getLengthTask
soit attendu.
Étape FIVE
Quand client.GetStringAsync
signale que son exécution est terminée, le traitement dans AccessTheWebAsync
est libéré de la suspension et peut continuer après l’instruction await. Les lignes de sortie suivantes représentent la reprise du traitement :
FIVE: Back in AccessTheWebAsync.
Task getStringTask is complete.
Processing the return statement.
Exiting from AccessTheWebAsync.
L’opérande de l’instruction return, urlContents.Length
, est stocké dans la tâche que AccessTheWebAsync
retourne. L’expression await récupère cette valeur à partir de getLengthTask
dans startButton_Click
.
L’illustration suivante présente le transfert du contrôle après l’exécution de client.GetStringAsync
(et de getStringTask
).
AccessTheWebAsync
s’exécute jusqu’à la fin et le contrôle retourne à startButton_Click
, qui attend que son exécution soit terminée.
Étape SIX
Quand AccessTheWebAsync
signale que son exécution est terminée, le traitement peut continuer après l’instruction await dans startButton_Async
. En fait, le programme n’a plus rien d’autre à faire.
Les lignes de sortie suivantes représentent la reprise du traitement dans startButton_Async
:
SIX: Back in startButton_Click.
Task getLengthTask is finished.
Result from AccessTheWebAsync is stored in contentLength.
About to display contentLength and exit.
L’expression await récupère de getLengthTask
la valeur entière qui est l’opérande de l’instruction return dans AccessTheWebAsync
. L’instruction suivante assigne cette valeur à la variable contentLength
.
Dim contentLength As Integer = Await getLengthTask
L’illustration suivante montre le retour du contrôle de AccessTheWebAsync
à startButton_Click
.