Partager via


Programmation asynchrone avec Async et Await (Visual Basic)

Vous pouvez éviter les goulots d’étranglement des performances et améliorer la réactivité globale de votre application à l’aide de la programmation asynchrone. Toutefois, les techniques traditionnelles d’écriture d’applications asynchrones peuvent être compliquées, ce qui les rend difficiles à écrire, déboguer et gérer.

Visual Studio 2012 a introduit une approche simplifiée, une programmation asynchrone, qui tire parti de la prise en charge asynchrone dans .NET Framework 4.5 et versions ultérieures, ainsi que dans Windows Runtime. Le compilateur effectue le travail difficile que le développeur a utilisé pour effectuer, et votre application conserve une structure logique qui ressemble à du code synchrone. Par conséquent, vous bénéficiez de tous les avantages de la programmation asynchrone avec une fraction de l’effort.

Cette rubrique fournit une vue d’ensemble du moment et de la façon d’utiliser la programmation asynchrone et inclut des liens vers des rubriques de support qui contiennent des détails et des exemples.

Async améliore la réactivité

La synchronisation est essentielle pour les activités potentiellement bloquantes, par exemple lorsque votre application accède au web. L’accès à une ressource web est parfois lent ou retardé. Si une telle activité est bloquée dans un processus synchrone, l’application entière doit attendre. Dans un processus asynchrone, l’application peut continuer avec d’autres travaux qui ne dépendent pas de la ressource web tant que la tâche potentiellement bloquante n’est pas terminée.

Le tableau suivant présente les zones typiques où la programmation asynchrone améliore la réactivité. Les API répertoriées à partir du .NET Framework 4.5 et de Windows Runtime contiennent des méthodes qui prennent en charge la programmation asynchrone.

Domaine d'application Prise en charge des API qui contiennent des méthodes asynchrones
Accès web HttpClient, SyndicationClient
Utilisation de fichiers StorageFile, , StreamWriterStreamReader, ,XmlReader
Utilisation d’images MediaCapture, BitmapEncoder, BitmapDecoder
Programmation WCF Opérations synchrones et asynchrones

Asynchrony prouve particulièrement utile pour les applications qui accèdent au thread d’interface utilisateur, car toutes les activités liées à l’interface utilisateur partagent généralement un thread. Si un processus est bloqué dans une application synchrone, tous sont bloqués. Votre application ne répond plus et vous pouvez conclure qu'elle a rencontré une défaillance, alors qu'elle attend simplement.

Lorsque vous utilisez des méthodes asynchrones, l’application continue de répondre à l’interface utilisateur. Vous pouvez redimensionner ou réduire une fenêtre, par exemple, ou fermer l’application si vous ne souhaitez pas attendre qu’elle se termine.

L’approche asynchrone ajoute l’équivalent d’une transmission automatique à la liste des options que vous pouvez choisir lors de la conception d’opérations asynchrones. Autrement dit, vous bénéficiez de tous les avantages de la programmation asynchrone traditionnelle, mais avec beaucoup moins d’efforts du développeur.

Les méthodes asynchrones sont plus faciles à écrire

Les mots clés Async et Await dans Visual Basic sont le cœur de la programmation asynchrone. En utilisant ces deux mots clés, vous pouvez utiliser des ressources dans .NET Framework ou Windows Runtime pour créer une méthode asynchrone presque aussi facilement que vous créez une méthode synchrone. Les méthodes asynchrones que vous définissez à l’aide Async et Await sont appelées méthodes asynchrones.

L’exemple suivant montre une méthode asynchrone. Presque tout dans le code doit vous sembler complètement familier. Les commentaires mentionnent les fonctionnalités que vous ajoutez pour créer l'asynchronie.

Vous trouverez un fichier d’exemple WPF (Windows Presentation Foundation) complet à la fin de cette rubrique, et vous pouvez télécharger l’exemple à partir d’Async Sample : Exemple de « Programmation asynchrone avec Async et Await ».

' Three things to note about writing an Async Function:
'  - The function has an Async modifier.
'  - Its return type is Task or Task(Of T). (See "Return Types" section.)
'  - As a matter of convention, its name ends in "Async".
Async Function AccessTheWebAsync() As Task(Of Integer)
    Using client As New HttpClient()
        ' Call and await separately.
        '  - AccessTheWebAsync can do other things while GetStringAsync is also running.
        '  - getStringTask stores the task we get from the call to GetStringAsync.
        '  - Task(Of String) means it is a task which returns a String when it is done.
        Dim getStringTask As Task(Of String) =
            client.GetStringAsync("https://learn.microsoft.com/dotnet")
        ' You can do other work here that doesn't rely on the string from GetStringAsync.
        DoIndependentWork()
        ' The Await operator suspends AccessTheWebAsync.
        '  - AccessTheWebAsync does not continue until getStringTask is complete.
        '  - Meanwhile, control returns to the caller of AccessTheWebAsync.
        '  - Control resumes here when getStringTask is complete.
        '  - The Await operator then retrieves the String result from getStringTask.
        Dim urlContents As String = Await getStringTask
        ' The Return statement specifies an Integer result.
        ' A method which awaits AccessTheWebAsync receives the Length value.
        Return urlContents.Length

    End Using

End Function

Si AccessTheWebAsync n'a aucun travail qu'il peut effectuer entre l'appel de GetStringAsync et l'attente de son achèvement, vous pouvez simplifier votre code en appelant et attendant dans l'instruction unique suivante.

Dim urlContents As String = Await client.GetStringAsync()

Les caractéristiques suivantes résument ce qui rend l’exemple précédent d’une méthode asynchrone :

  • La signature de méthode inclut un Async modificateur.

  • Le nom d’une méthode asynchrone, par convention, se termine par un suffixe « Async ».

  • Le type de retour est l’un des types suivants :

    • Task(Of TResult) si votre méthode a une instruction return dans laquelle l’opérande a le type TResult.
    • Task si votre méthode n’a pas d’instruction return ou n’a pas d’instruction return sans opérande.
    • Sub si vous écrivez un gestionnaire d'événements asynchrone.

    Pour plus d’informations, consultez « Types et paramètres de retour » plus loin dans cette rubrique.

  • La méthode inclut généralement au moins une expression await, qui marque un point où la méthode ne peut pas continuer tant que l’opération asynchrone attendue n’est pas terminée. En attendant, la méthode est suspendue et le contrôle retourne à l’appelant de la méthode. La section suivante de cette rubrique illustre ce qui se passe au point de suspension.

Dans les méthodes asynchrones, vous utilisez les mots clés et types fournis pour indiquer ce que vous souhaitez faire, et le compilateur effectue le reste, y compris suivre ce qui doit se produire lorsque le contrôle retourne à un point d’attente dans une méthode suspendue. Certains processus de routine, tels que les boucles et la gestion des exceptions, peuvent être difficiles à gérer dans le code asynchrone traditionnel. Dans une méthode asynchrone, vous écrivez ces éléments autant que vous le feriez dans une solution synchrone, et le problème est résolu.

Pour plus d’informations sur l’asynchronie dans les versions précédentes du .NET Framework, consultez TPL et Programmation asynchrone .NET Framework traditionnelle.

Que se passe-t-il dans une méthode Async

La chose la plus importante à comprendre dans la programmation asynchrone est la façon dont le flux de contrôle passe de la méthode à la méthode. Le diagramme suivant vous guide tout au long du processus :

Diagramme montrant le suivi d’un programme asynchrone.

Les nombres du diagramme correspondent aux étapes suivantes :

  1. Un gestionnaire d’événements appelle et attend la AccessTheWebAsync méthode asynchrone.

  2. AccessTheWebAsync crée une HttpClient instance et appelle la GetStringAsync méthode asynchrone pour télécharger le contenu d’un site web sous forme de chaîne.

  3. Quelque chose se produit dans GetStringAsync ce qui suspend sa progression. Elle peut être obligée d'attendre la fin d'un téléchargement sur un site Web ou de toute autre activité bloquante. Pour éviter de bloquer les ressources, GetStringAsync donne le contrôle à son appelant. AccessTheWebAsync

    GetStringAsync retourne une tâche(Of TResult) où TResult est une chaîne et AccessTheWebAsync affecte la tâche à la getStringTask variable. La tâche représente le processus en cours de l'appel de GetStringAsync, avec l'engagement de produire une valeur de chaîne réelle lorsque le travail est terminé.

  4. Comme getStringTask n’a pas encore été attendu, AccessTheWebAsync peut continuer avec d’autres travaux qui ne dépendent pas du résultat final de GetStringAsync. Ce travail est représenté par un appel à la méthode DoIndependentWorksynchrone.

  5. DoIndependentWork est une méthode synchrone qui effectue son travail et retourne à son appelant.

  6. AccessTheWebAsync n’a plus de travail à exécuter sans un résultat de getStringTask. AccessTheWebAsync Souhaite ensuite calculer et retourner la longueur de la chaîne téléchargée, mais la méthode ne peut pas calculer cette valeur tant que la méthode n’a pas la chaîne.

    Par conséquent, AccessTheWebAsync utilise un opérateur await pour suspendre sa progression et pour donner le contrôle à la méthode appelée AccessTheWebAsync. AccessTheWebAsync retourne un Task(Of Integer) à l’appelant. La tâche représente une promesse de produire un résultat entier qui est la longueur de la chaîne téléchargée.

    Remarque

    Si GetStringAsync (et par conséquent getStringTask) est terminé avant que AccessTheWebAsync ne l'attende, le contrôle reste dans AccessTheWebAsync. Les frais de suspension et de retour à AccessTheWebAsync seraient gaspillés si le processus asynchrone appelé (getStringTask) est déjà terminé et AccessTheWebSync ne nécessite pas d’attendre le résultat final.

    À l’intérieur de l’appelant (le gestionnaire d’événements dans cet exemple), le modèle de traitement se poursuit. L’appelant peut effectuer d’autres tâches qui ne dépendent pas du résultat de AccessTheWebAsync avant d’attendre ce résultat, ou bien il peut attendre immédiatement. Le gestionnaire d’événements attend AccessTheWebAsync, et AccessTheWebAsync attend GetStringAsync.

  7. GetStringAsync se termine et génère un résultat de chaîne. Le résultat de chaîne n'est pas retourné par l'appel de GetStringAsync de la façon à laquelle vous pourriez vous attendre. (N’oubliez pas que la méthode a déjà retourné une tâche à l’étape 3.) Au lieu de cela, le résultat de la chaîne est stocké dans la tâche qui représente l’achèvement de la méthode. getStringTask L’opérateur await récupère le résultat à partir de getStringTask. L’instruction d’affectation affecte le résultat récupéré à urlContents.

  8. Quand AccessTheWebAsync a le résultat sous forme de chaîne, la méthode peut calculer la longueur de cette chaîne. Le travail de AccessTheWebAsync est également terminé, et ensuite le gestionnaire d’événements en attente peut reprendre. Dans l’exemple complet à la fin de la rubrique, vous pouvez confirmer que le gestionnaire d’événements récupère et imprime la valeur du résultat de longueur.

Si vous débutez avec la programmation asynchrone, prenez une minute pour prendre en compte la différence entre le comportement synchrone et asynchrone. Une méthode synchrone retourne une fois son travail terminé (étape 5), mais une méthode asynchrone retourne une valeur de tâche lorsque son travail est suspendu (étapes 3 et 6). Lorsque la méthode asynchrone termine son travail, la tâche est marquée comme terminée et le résultat, le cas échéant, est stocké dans la tâche.

Pour plus d’informations sur le flux de contrôle, consultez Flux de contrôle dans les programmes asynchrones (Visual Basic).

Méthodes asynchrones d’API

Vous vous demandez peut-être où trouver des méthodes telles que GetStringAsync celles qui prennent en charge la programmation asynchrone. .NET Framework 4.5 ou version ultérieure contient de nombreux membres qui fonctionnent avec Async et Await. Vous pouvez reconnaître ces membres par le suffixe « Async » attaché au nom du membre et un type de retour de Task ou Task(Of TResult). Par exemple, la System.IO.Stream classe contient des méthodes telles que CopyToAsync, ReadAsyncet WriteAsync en même temps que les méthodes CopyTosynchrones , Readet Write.

Windows Runtime contient également de nombreuses méthodes que vous pouvez utiliser avec Async et Await dans les applications Windows. Pour plus d’informations et d’exemples de méthodes, consultez Appeler des API asynchrones en C# ou Visual Basic, programmation asynchrone (applications Windows Runtime) et WhenAny : Pontage entre .NET Framework et Windows Runtime.

Fils de discussion

Les méthodes asynchrones sont destinées à être des opérations non bloquantes. Une Await expression dans une méthode asynchrone ne bloque pas le thread actuel pendant l’exécution de la tâche attendue. Au lieu de cela, l'expression inscrit le reste de la méthode comme continuation et retourne le contrôle à l'appelant de la méthode async.

Les Async mots clés et Await ne provoquent pas la création de threads supplémentaires. Les méthodes asynchrones ne nécessitent pas de multithreading, car une méthode asynchrone ne s’exécute pas sur son propre thread. La méthode s’exécute sur le contexte de synchronisation actuel et utilise le temps sur le thread uniquement lorsque la méthode est active. Vous pouvez utiliser Task.Run pour déplacer le travail lié au processeur vers un thread d’arrière-plan, mais un thread d’arrière-plan n’aide pas avec un processus qui attend simplement que les résultats soient disponibles.

L’approche basée sur async pour la programmation asynchrone est préférable aux approches existantes dans la plupart des cas. En particulier, cette approche est meilleure que BackgroundWorker pour les opérations liées aux E/S, car le code est plus simple et vous n’avez pas à vous protéger contre les conditions de concurrence. En combinaison avec Task.Run, la programmation asynchrone est meilleure que BackgroundWorker pour les opérations liées au processeur, car la programmation asynchrone sépare les détails de coordination de l’exécution de votre code du travail qui Task.Run transfère vers le threadpool.

Async et Await

Si vous spécifiez qu’une méthode est une méthode asynchrone à l’aide d’un modificateur Async , vous activez les deux fonctionnalités suivantes.

  • La méthode asynchrone marquée peut utiliser Await pour désigner des points de suspension. L’opérateur await indique au compilateur que la méthode asynchrone ne peut pas continuer après ce point tant que le processus asynchrone attendu n’est pas terminé. En attendant, le contrôle retourne à l’appelant de la méthode asynchrone.

    La suspension d’une méthode asynchrone à une Await expression ne constitue pas une sortie de la méthode et Finally les blocs ne s’exécutent pas.

  • La méthode async marquée peut elle-même être attendue par les méthodes qui l'appellent.

Une méthode asynchrone contient généralement une ou plusieurs occurrences d’un Await opérateur, mais l’absence d’expressions Await ne provoque pas d’erreur du compilateur. Si une méthode asynchrone n’utilise pas d’opérateur Await pour marquer un point de suspension, la méthode s’exécute comme une méthode synchrone, malgré le Async modificateur. Le compilateur émet un avertissement pour ces méthodes.

Async et Await sont des mots clés contextuels. Pour plus d’informations et d’exemples, consultez les rubriques suivantes :

Types et paramètres de retour

Dans la programmation .NET Framework, une méthode asynchrone retourne généralement un Task ou un Task(Of TResult). À l’intérieur d’une méthode asynchrone, un opérateur Await est appliqué à une tâche retournée par un appel à une autre méthode asynchrone.

Vous spécifiez Task(Of TResult) comme type de retour si la méthode contient une instruction Return qui spécifie un opérande de type TResult.

Vous utilisez Task comme type de retour si la méthode n’a pas d’instruction return ou a une instruction return qui ne retourne pas d’opérande.

L’exemple suivant montre comment déclarer et appeler une méthode qui retourne une tâche(of TResult) ou un Task:

' Signature specifies Task(Of Integer)
Async Function TaskOfTResult_MethodAsync() As Task(Of Integer)

    Dim hours As Integer
    ' . . .
    ' Return statement specifies an integer result.
    Return hours
End Function

' Calls to TaskOfTResult_MethodAsync
Dim returnedTaskTResult As Task(Of Integer) = TaskOfTResult_MethodAsync()
Dim intResult As Integer = Await returnedTaskTResult
' or, in a single statement
Dim intResult As Integer = Await TaskOfTResult_MethodAsync()

' Signature specifies Task
Async Function Task_MethodAsync() As Task

    ' . . .
    ' The method has no return statement.
End Function

' Calls to Task_MethodAsync
Task returnedTask = Task_MethodAsync()
Await returnedTask
' or, in a single statement
Await Task_MethodAsync()

Chaque tâche retournée représente le travail en cours. Une tâche encapsule des informations sur l’état du processus asynchrone et, éventuellement, le résultat final du processus ou l’exception que le processus déclenche s’il ne réussit pas.

Une méthode asynchrone peut également être une Sub méthode. Ce type de retour est utilisé principalement pour définir des gestionnaires d’événements, où un type de retour est requis. Les gestionnaires d’événements asynchrones servent souvent de point de départ pour les programmes asynchrones.

Une méthode async qui est une procédure Sub ne peut pas être attendue, et l’appelant ne peut capturer aucune exception levée par la méthode.

Une méthode asynchrone ne peut pas déclarer de paramètres ByRef , mais la méthode peut appeler des méthodes qui ont de tels paramètres.

Pour plus d’informations et d’exemples, consultez Types de retour asynchrones (Visual Basic). Pour plus d’informations sur la façon d’intercepter des exceptions dans des méthodes asynchrones, consultez Try...Catch...Finally Statement.

Les API asynchrones de la programmation Windows Runtime ont l’un des types de retour suivants, qui sont similaires aux tâches :

Pour plus d’informations et un exemple, consultez Appeler des API asynchrones en C# ou Visual Basic.

Conventions d’affectation de noms

Par convention, vous ajoutez « Async » aux noms des méthodes qui ont un Async modificateur.

Vous pouvez ignorer la convention dans laquelle un événement, une classe de base ou un contrat d’interface suggère un autre nom. Par exemple, vous ne devez pas renommer les gestionnaires d’événements courants, tels que Button1_Click.

Rubriques et exemples connexes (Visual Studio)

Titre Descriptif Échantillon
Procédure pas à pas : accès au web à l’aide d’Async et Await (Visual Basic) Montre comment convertir une solution WPF synchrone en solution WPF asynchrone. L’application télécharge une série de sites web. Exemple asynchrone : programmation asynchrone avec Async et Await (Visual Basic)
Procédure : étendre la procédure pas à pas asynchrone à l’aide de Task.WhenAll (Visual Basic) Ajoute Task.WhenAll à la procédure précédente. L'utilisation de WhenAll démarre tous les téléchargements en même temps.
Guide pratique pour effectuer plusieurs requêtes web en parallèle à l’aide d’Async et Await (Visual Basic) Montre comment démarrer plusieurs tâches en même temps. Exemple asynchrone : Effectuer plusieurs requêtes web en parallèle
Types de retour asynchrones (Visual Basic) Illustre les types que les méthodes asynchrones peuvent retourner et expliquer quand chaque type est approprié.
Flux de contrôle dans les programmes asynchrones (Visual Basic) Trace en détail le flux de contrôle à travers une série d'expressions 'await' dans un programme asynchrone. Exemple asynchrone : Flux de contrôle dans les programmes asynchrones
Fine-Tuning votre application asynchrone (Visual Basic) Montre comment ajouter les fonctionnalités suivantes à votre solution asynchrone :

- Annuler une tâche asynchrone ou une liste de tâches (Visual Basic)
- Annuler des tâches asynchrones après une période de temps (Visual Basic)
- Annuler les tâches asynchrones restantes une fois qu’une tâche est terminée (Visual Basic)
- Démarrez plusieurs tâches asynchrones et traitez-les à mesure qu’elles se terminent (Visual Basic)
Exemple asynchrone : réglage précis de votre application
Gestion de la réentrance dans Async Apps (Visual Basic) Montre comment gérer les cas dans lesquels une opération asynchrone active est redémarrée pendant son exécution.
WhenAny : Pontage entre .NET Framework et Windows Runtime Montre comment établir un pont entre les types de tâches dans le .NET Framework et les IAsyncOperations dans le Windows Runtime afin de pouvoir utiliser WhenAny avec une méthode Windows Runtime. Exemple asynchrone : Pontage entre .NET et Windows Runtime (AsTask et WhenAny)
Annulation Asynch : combler l'écart entre .NET Framework et Windows Runtime Montre comment établir un pont entre les types de tâches dans le .NET Framework et les IAsyncOperations dans le Windows Runtime afin de pouvoir utiliser CancellationTokenSource avec une méthode Windows Runtime. Exemple Async : transition entre .NET et Windows Runtime (AsTask & &Annulation)
Utilisation d’Async pour l’accès aux fichiers (Visual Basic) Répertorie et explique les avantages de l'utilisation d'async et d'await pour accéder aux fichiers.
Modèle asynchrone basé sur des tâches (TAP) Décrit un nouveau modèle pour la synchronisation dans le .NET Framework. Le modèle est basé sur Task et sur les types Task(Of TResult).

Exemple complet

Le code suivant est le fichier MainWindow.xaml.vb de l’application WPF (Windows Presentation Foundation) que cette rubrique traite. Vous pouvez télécharger l’exemple à partir de l’exemple Async : exemple à partir de « Programmation asynchrone avec Async et Await ».


Imports System.Net.Http

' Example that demonstrates Asynchronous Programming with Async and Await.
' It uses HttpClient.GetStringAsync to download the contents of a website.
' Sample Output:
' Working . . . . . . .
'
' Length of the downloaded string: 39678.

Class MainWindow

    ' Mark the event handler with Async so you can use Await in it.
    Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)

        ' Call and await immediately.
        ' StartButton_Click suspends until AccessTheWebAsync is done.
        Dim contentLength As Integer = Await AccessTheWebAsync()

        ResultsTextBox.Text &= $"{vbCrLf}Length of the downloaded string: {contentLength}.{vbCrLf}"

    End Sub


    ' Three things to note about writing an Async Function:
    '  - The function has an Async modifier.
    '  - Its return type is Task or Task(Of T). (See "Return Types" section.)
    '  - As a matter of convention, its name ends in "Async".
    Async Function AccessTheWebAsync() As Task(Of Integer)

        Using client As New HttpClient()

            ' Call and await separately.
            '  - AccessTheWebAsync can do other things while GetStringAsync is also running.
            '  - getStringTask stores the task we get from the call to GetStringAsync.
            '  - Task(Of String) means it is a task which returns a String when it is done.
            Dim getStringTask As Task(Of String) =
                client.GetStringAsync("https://learn.microsoft.com/dotnet")

            ' You can do other work here that doesn't rely on the string from GetStringAsync.
            DoIndependentWork()

            ' The Await operator suspends AccessTheWebAsync.
            '  - AccessTheWebAsync does not continue until getStringTask is complete.
            '  - Meanwhile, control returns to the caller of AccessTheWebAsync.
            '  - Control resumes here when getStringTask is complete.
            '  - The Await operator then retrieves the String result from getStringTask.
            Dim urlContents As String = Await getStringTask

            ' The Return statement specifies an Integer result.
            ' A method which awaits AccessTheWebAsync receives the Length value.
            Return urlContents.Length

        End Using

    End Function

    Sub DoIndependentWork()
        ResultsTextBox.Text &= $"Working . . . . . . .{vbCrLf}"
    End Sub

End Class

Voir aussi