# Programmation C sharp/Fonctions asynchrones

L'appel à une fonction se fait de manière synchrone : aucune autre instruction n'est exécutée avant que la fonction ne retourne une valeur. Cependant certaines fonctions prennent beaucoup de temps, en particulier les opérations d'entrées-sorties, et les fonctions de communication par réseau informatique.
Pour ce genre de fonction, l'API .Net possède souvent deux versions de la méthode :
* Une méthode synchrone qui attend la fin de l'opération avant d'en retourner le résultat,
* Une méthode asynchrone demandant au pool de threads standard d'effectuer l'opération, puis retourne immédiatement à la méthode appelante.

## Syntaxe et utilisation des méthodes asynchrones

Une méthode synchrone est déclarée selon la syntaxe suivante :
La version asynchrone utilise deux autres méthodes. La première commence par Begin et demande au pool de threads standard d'effectuer l'opération. Une fois l'opération terminée, un delegate est appelé. Celui-ci appelle alors la méthode dont le nom commence par End pour récupérer la valeur retournée par la méthode asynchrone.
Ces deux méthodes ont la syntaxe suivante :
Les arguments de la méthode synchrone se retrouvent répartis entre les deux méthodes :
* Les paramètres passés par valeur sont passés à la méthode Begin,
* Les paramètres de sorties (out et ref) sont passés à la méthode End.
La méthode Begin possède deux arguments supplémentaires :
* Un delegate de type AsyncCallback appelé quand l'opération est terminée (celui-ci doit alors appeler la méthode End correspondante),
* Un objet à transmettre au delegate.

## Le delegate AsyncCallback

La syntaxe du delegate AsyncCallback est la suivante :
Le paramètre result est une interface de type IAsyncResult correspondant à celui retourné par la méthode Begin, et doit être passé à la méthode End.

## L'interface IAsyncResult

L'interface IAsyncResult possède les propriétés en lecture seule suivantes :
* Propriété généralement utilisée par le delegué appelé quand l'opération est terminée :

### object AsyncState

    Cet objet correspond à celui transmis à la méthode Begin.
* Propriétés généralement utilisées par le code appelant la méthode Begin de l'opération asynchrone :

### WaitHandle AsyncWaitHandle

    Cet objet de synchronisation est mis dans l'état signalé quand l'opération est terminée.

### bool IsCompleted

    Ce booléen vaut true (vrai) lorsque l'opération est terminée.

### bool CompletedSynchronously

    Ce booléen vaut true (vrai) si l'opération s'est terminée de manière synchrone.
La propriété AsyncWaitHandle permet de lancer une opération asynchrone, d'effectuer d'autres traitements durant l'opération en cours, et finalement attendre la fin de l'opération si elle ne s'est pas déjà terminée, en testant la propriété IsCompleted.

## Fonctions asynchrones et tâches

Depuis C#5.0, il est possible de simplifier la programmation asynchrone avec les mots-clés async et await.

### Déclaration d'une fonction asynchrone

Le mot-clé async est utilisé dans la déclaration d'une méthode pour indiquer qu'elle est asynchrone. Cela signifie que son exécution comporte une longue tâche, et qu'elle peut utiliser le mot-clé await pour attendre une autre tâche. Le type de sa valeur de retour T est modifié en Task<T> indiquant que la fonction asynchrone retourne désormais une tâche dont le résultat est de type T.
Par convention, le nom d'une fonction asynchrone se termine par "Async".
Exemple :

### Appeler et attendre une tâche

Appeler une fonction asynchrone est une façon de créer une nouvelle tâche :
L'appel de l'exemple précédent se fait de manière asynchrone, récupérant un objet tâche. La méthode peut faire autre chose avant d'attendre et récupérer le résultat explicitement en utilisant await. L'utilisation du mot-clé await dans une méthode n'est autorisé que si la méthode est déclarée elle-même asynchrone avec async.
La hiérarchie des appels est donc une chaîne de méthodes asynchrones (async -> attendre avec await, donc méthode async, ...), qui peut toutefois s'arrêter soit en n'utilisant pas le mot-clé await si on n'a pas besoin d'attendre la fin, soit en utilisant la méthode Wait de la classe Task comme dans cet exemple :

### Créer une tâche

La classe Task possède des méthodes statiques pour créer des tâches :
* La méthode Task.Run( function ) crée une tâche pour exécuter la fonction donnée en argument.
* La méthode Task.Wait( délai_en_millisecondes ) crée une tâche pour attendre le nombre de millisecondes spécifié.
Exemple pour simuler le téléchargement de page des exemples précédents :