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/await
avant l'heure 📆2007 :
Async<'T>
F♯2012 :
Task<T>
.NET et patternasync
/await
2017 :
Promise
JavaScript et patternasync
/await
Méthodes renvoyant un objet Async
Async
Async.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
AsyncRead(buffer: byte[], ?offset: int, ?count: int) : Async<int>
AsyncWrite(buffer: byte[], ?offset: int, ?count: int) : Async<unit>
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 -unit
si omislet!
(prononcer « let bang ») → accès au résultat d'un sous-calcul async (≃await
en C♯)use!
→ idemuse
(gestion d'unIDisposable
) +let!
do!
→ idemlet!
pour calcul async sans retour (Async<unit>
)
Usage inapproprié de Async.RunSynchronously
Async.RunSynchronously
Async.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.Parallel
Async.Parallel(computations: seq<Async<'T>>, ?maxBranches) : Async<'T[]>
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.StartChild
Async.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
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.CancellationToken
puisct.IsCancellationRequested
Explicite global :
Async.OnCancel(callback)
Exemple :
Résultat :
Dernière mise à jour
Cet article vous a-t-il été utile ?