Workflow asynchrone
Besoins
Ne pas bloquer le thread courant en attendant un calcul long
Permettre calculs en parallèle
Indiquer qu'un calcul peut prendre du temps
Type Async<'T>
Async<'T>Représente un calcul asynchrone
Similaire au pattern
async/awaitavant l'heure 📆2007 :
Async<'T>F♯2012 :
Task<T>.NET et patternasync/await2017 :
PromiseJavaScript et patternasync/await
Méthodes renvoyant un objet Async
AsyncAsync.AwaitTask(task: Task or Task<'T>) : Async<'T>
Conversion d'une
Task(.NET) enAsync(F♯)
Async.Sleep(milliseconds or TimeSpan) : Async<unit>
≃
await Task.Delay()≠Thread.Sleep→ ne bloque pas le thread courant
FSharp.Control.CommonExtensions : étend le type System.IO.Stream
AsyncRead(buffer: byte[], ?offset: int, ?count: int) : Async<int>AsyncWrite(buffer: byte[], ?offset: int, ?count: int) : Async<unit>
FSharp.Control.WebExtensions : étend le type System.Net.WebClient
AsyncDownloadData(address: Uri) : Async<byte[]>AsyncDownloadString(address: Uri) : Async<string
Lancement d'un calcul async
Async.RunSynchronously(calc: Async<'T>, ?timeoutMs: int, ?cancellationToken) : 'T → Attend la fin du calcul mais bloque le thread appelant ! (≠ await C♯) ⚠️
Async.Start(operation: Async<unit>, ?cancellationToken) : unit
→ Exécute l'opération en background (sans bloqué le thread appelant)
⚠️ Si une exception survient, elle est "avalée" !
Async.StartImmediate(calc: Async<'T>, ?cancellationToken) : unit
→ Exécute le calcul dans le thread appelant !
💡 Pratique dans une GUI pour la mettre à jour : barre de progression...
Async.StartWithContinuations(calc, continuations..., ?cancellationToken)
→ Idem Async.RunSynchronously
⚠️ ... avec 3 callbacks de continuation : en cas de succès ✅, d'exception 💥 et d'annulation 🛑
Bloc async { expression }
async { expression }A.k.a. Async workflow
Syntaxe pour écrire de manière séquentielle un calcul asynchrone → Le résultat du calcul est wrappé dans un objet Async
Mots clés
return→ valeur finale du calcul -unitsi omislet!(prononcer « let bang ») → accès au résultat d'un sous-calcul async (≃awaiten C♯)use!→ idemuse(gestion d'unIDisposable) +let!do!→ idemlet!pour calcul async sans retour (Async<unit>)
Usage inapproprié de Async.RunSynchronously
Async.RunSynchronouslyAsync.RunSynchronously lance le calcul et renvoie son résultat MAIS en bloquant le thread appelant ! Ne l'utiliser qu'en « bout de chaîne » et pas pour unwrap des calculs asynchrones intermédiaires ! Utiliser plutôt un bloc async.
Calculs en parallèle
Async.Parallel
Async.ParallelAsync.Parallel(computations: seq<Async<'T>>, ?maxBranches) : Async<'T[]>
≃ Task.WhenAll : modèle Fork-Join
Fork : calculs lancés en parallèle
Attente de la terminaison de tous les calculs
Join : agrégation des résultats (qui sont du même type)
dans le même ordre que les calculs
Async.StartChild
Async.StartChildAsync.StartChild(calc: Async<'T>, ?timeoutMs: int) : Async<Async<'T>>
Permet de lancer en parallèle plusieurs calculs
→ ... dont les résultats sont de types différents (≠ Async.Parallel)
S'utilise dans bloc async avec 2 let! par calcul enfant (cf. Async<Async<'T>>)
Annulation conjointe 📍 Annulation d'une tâche → Le calcul enfant partage le jeton d’annulation du calcul parent
Exemple :
Soit le fonction delay
→ qui renvoie la valeur spécifiée x
→ au bout de ms millisecondes
💡 Minutage avec la directive FSI #time (doc)
Annulation d'une tâche
Se base sur un CancellationToken/Source par défaut ou explicite :
Async.RunSynchronously(computation, ?timeout, ?cancellationToken)Async.Start(computation, ?cancellationToken)
Déclencher l'annulation
Token explicite +
cancellationTokenSource.Cancel()Token explicite avec timeout
new CancellationTokenSource(timeout)Token par défaut :
Async.CancelDefaultToken()→OperationCanceledException💥
Vérifier l'annulation
Implicite : à chaque mot clé dans bloc async :
let,let!,for...Explicite local :
let! ct = Async.CancellationTokenpuisct.IsCancellationRequestedExplicite global :
Async.OnCancel(callback)
Exemple :
Résultat :
Last updated
Was this helpful?