Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
FSharp.Core 11 ajoute des fonctions pour l’interopérabilité des tâches, les transformations de résultats et la concurrence limitée. Utilisez-les avec des flux de travail asynchrones et des expressions de tâche existants ; ils ne nécessitent pas le prototype runtime-async.
Await .NET opérations à partir d’async
Pour démarrer une opération de .NET avec le jeton d'annulation du flux de travail asynchrone, passez une fabrique à Async.StartTaskImmediate:
open System.IO
let tryReadFile path =
async {
try
let! contents =
Async.StartTaskImmediate(fun ct -> File.ReadAllTextAsync(path, ct))
return Some contents
with :? FileNotFoundException ->
return None
}
Le fichier lu reçoit le jeton d’annulation du flux de travail. Un fichier manquant retourne None; une lecture réussie renvoie Some contents. Le flux de travail attend la fin, y compris l’annulation et le nettoyage.
Utilisez Async.Await quand vous disposez déjà d’une valeur semblable à une tâche. Les deux API propagent directement l’exception sous-jacente unique d’une tâche défectueuse. Un agrégat avec plusieurs exceptions internes reste un agrégat.
Async.AwaitTask conserve son comportement d’habillage d’exception existant.
| API | Formes d’argument/résultat prises en charge |
|---|---|
Async.Await |
Task<'T> -> Async<'T>; Task -> Async<unit> |
Async.Await |
ValueTask<'T> -> Async<'T>; ValueTask -> Async<unit> |
Async.Await |
Surcharge de type tâche inline à l’aide du GetAwaiter protocole. |
Async.StartTaskImmediate |
(CancellationToken -> Task<'T>) -> Async<'T>; retours Async<unit>non génériques Task . |
Async.StartTaskImmediate |
Surcharges d’usine correspondantes ValueTask, ValueTask<'T>et de type tâche. |
Task.startAsyncImmediate |
CancellationToken -> Async<'T> -> Task<'T> |
Async.RunSynchronouslyImmediate |
Async<'T> * ?cancellationToken: CancellationToken -> 'T |
Async.RunSynchronouslyImmediate démarre sur le thread appelant, contrairement Async.RunSynchronously à un thread de premier plan, et bloque l’achèvement. Il n’a aucun paramètre de délai d’expiration. Préférer la composition asynchrone sur les threads d’interface utilisateur et de requête.
Exposer un flux de travail asynchrone en tant que tâche
Pour offrir le flux de travail de lecture de fichiers ci-dessus aux appelants basés sur des tâches, acceptez un jeton d’annulation et transmettez-le :Task.startAsyncImmediate
let tryReadFileTask (path: string) (ct: CancellationToken) =
tryReadFile path |> Task.startAsyncImmediate ct
Le pont retourne Task<string option> et propage l’annulation. Il commence sur le thread appelant jusqu’à la première suspension ; les continuations ultérieures n’ont pas besoin d’utiliser ce thread.
Concurrence liée
Une Async<'T> valeur décrit le travail différé. Une tâche représente généralement une opération qui a déjà démarré. Pour limiter l’utilisation des ressources, décrivez le travail des tâches en tant que fabriques plutôt que les tâches en cours d’exécution :
open System.IO
open System.Threading
let readFiles (paths: seq<string>) (ct: CancellationToken) =
paths
|> Seq.map (fun path ->
fun token -> File.ReadAllTextAsync(path, token))
|> Task.parallelLimit 4 ct
Task.parallelLimit commence simultanément à la limite positive des calculs et retourne des résultats dans l’ordre d’entrée. L’ordre de démarrage et l’ordre de saisie semi-automatique ne sont pas spécifiés. Pour l’accès concurrentiel supérieur à un, chaque fabrique reçoit un jeton lié qui signale également l’échec frère ; pour l’exécution séquentielle, il reçoit directement le jeton fourni.
Lorsqu’une erreur de calcul est demandée pour ses frères. Les opérations doivent observer leurs jetons pour coopérer. Si plusieurs calculs échouent, une exception est propagée ; ne dépend pas de l’échec qui gagne.
| Fonction | Forme de signature |
|---|---|
Task.parallelLimit |
int -> CancellationToken -> seq<CancellationToken -> Task<'T>> -> Task<'T[]> |
Task.parallelDoLimit |
int -> CancellationToken -> seq<CancellationToken -> Task<unit>> -> Task<unit> |
Task.sequential |
CancellationToken -> seq<CancellationToken -> Task<'T>> -> Task<'T[]> |
Task.sequentialDo |
CancellationToken -> seq<CancellationToken -> Task<unit>> -> Task<unit> |
Async.parallelLimit |
int -> seq<Async<'T>> -> Async<'T[]> |
Async.parallelDoLimit |
int -> seq<Async<unit>> -> Async<unit> |
Async.sequentialDo |
seq<Async<unit>> -> Async<unit> |
Les Async fonctions circulent le jeton d’annulation ambiant du flux de travail. Existant Async.Parallel (y compris son option de limite d’accès concurrentiel) et Async.Sequential reste disponible. Les Do variantes exposent un unit résultat lorsque vous n’avez besoin que de la saisie semi-automatique. Une limite de concurrence n’est pas un limiteur de débit : les opérations rapides peuvent toujours produire de nombreuses requêtes par seconde.
Transformer les résultats et récupérer à partir d’erreurs
Les Microsoft.FSharp.Control.Asyncmodules et ValueTask les modules Taskexposent ces fonctions qualifiées.
M<'T> dans la colonne de forme correspond au type de calcul correspondant, et non à une abréviation de type F#.
| Fonctions qualifiées | Forme |
|---|---|
Async.result, Task.result, ValueTask.result |
'T -> M<'T> |
Async.map, Task.map, ValueTask.map |
('T -> 'U) -> M<'T> -> M<'U> |
Async.bind, Task.bind, ValueTask.bind |
('T -> M<'U>) -> M<'T> -> M<'U> |
Async.ignore<'T>, Task.ignore<'T>, ValueTask.ignore<'T> |
M<'T> -> M<unit>; argument de type d’entrée explicite requis. |
Async.catchWith, Task.catchWith, ValueTask.catchWith |
(exn -> 'T) -> M<'T> -> M<'T> |
Async.catch, Task.catch, ValueTask.catch |
M<'T> -> M<Result<'T, exn>> |
Async.empty, Task.empty, ValueTask.empty |
M<unit> |
Task.ofValueTask |
ValueTask<'T> -> Task<'T> |
ValueTask.ofTask |
Task<'T> -> ValueTask<'T> |
Par exemple, mappez le contenu d’un fichier à une longueur, puis représentez un échec de lecture en tant que Result:
open System.IO
open System.Threading
let fileLength (path: string) (ct: CancellationToken) =
File.ReadAllTextAsync(path, ct)
|> Task.map String.length
|> Task.catch
Un fichier contenant Report 1 des données .Ok 8 Un fichier manquant donne un Error fichier contenant un FileNotFoundException. Pour ignorer une valeur réussie au lieu de la transformer, spécifiez le type d’entrée lorsque vous appelez ignore:
let completion: System.Threading.Tasks.Task<unit> =
Task.result 42 |> Task.ignore<int>
catchWith fournit une valeur de remplacement pour une défaillance sans annulation ; il n’exécute pas un autre calcul asynchrone.
catch renvoie Ok ou Error. L’annulation n’est pas convertie en valeur d’erreur ou transmise au gestionnaire de récupération.
Task.empty est un Task<unit>, pas le non générique Task.CompletedTask.
Contrairement aux minuscules, les retours Async.catchChoiceexistants Async.Catch . La récupération gère les échecs du calcul fourni, et non les exceptions synchrones levées avant l’appel. Async reste différé ; les tâches restent impatientes.
Disponibilité de ValueTask et de bibliothèque
Les API ValueTask nécessitent la génération ou net10.0 la netstandard2.1 génération de FSharp.Core 11. Consultez la sélection cible principale.
Observez le contrat de consommation unique ValueTask : consommez chaque valeur une seule fois, et non par le biais d’attentes ou de pipelines distincts. Pour les attentes répétées, appelez Task.ofValueTask une seule fois et réutilisez uniquement la tâche résultante.