Asynchrone en taakfuncties

FSharp.Core 11 voegt functies toe voor taakinteroperabiliteit, resultaattransformaties en gebonden gelijktijdigheid. Gebruik deze met bestaande asynchrone werkstromen en taakexpressies; ze hebben geen runtime-asynchroon prototype nodig.

Wachten op .NET bewerkingen vanaf asynchroon

Als u een .NET bewerking wilt starten met het annuleringstoken van de asynchrone werkstroom, geeft u een factory door aanAsync.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
    }

Het bestand dat wordt gelezen, ontvangt het annuleringstoken van de werkstroom. Een ontbrekend bestand retourneert None; een geslaagde leesbewerking retourneert Some contents. De werkstroom wacht op voltooiing, inclusief annulering en opschoning.

Gebruik Async.Await deze optie wanneer u al een taakachtige waarde hebt. Beide API's doorgeven de enkele onderliggende uitzondering van een defecte taak rechtstreeks. Een aggregaties met meerdere binnenste uitzonderingen blijft een aggregaties. Async.AwaitTask behoudt het bestaande gedrag voor uitzonderingsterugloop.

API Ondersteunde argument-/resultaatshapes
Async.Await Task<'T> -> Async<'T>; Task -> Async<unit>
Async.Await ValueTask<'T> -> Async<'T>; ValueTask -> Async<unit>
Async.Await Inline-taakachtige overbelasting met behulp van het GetAwaiter protocol.
Async.StartTaskImmediate (CancellationToken -> Task<'T>) -> Async<'T>; niet-generieke Task retourneert Async<unit>.
Async.StartTaskImmediate Overeenkomende ValueTask, ValueTask<'T>en taakachtige fabrieksoverbelastingen.
Task.startAsyncImmediate CancellationToken -> Async<'T> -> Task<'T>
Async.RunSynchronouslyImmediate Async<'T> * ?cancellationToken: CancellationToken -> 'T

Async.RunSynchronouslyImmediate begint op de aanroepende thread, in tegenstelling tot Async.RunSynchronously een voorgrondthread en blokken voor voltooiing. Er is geen time-outparameter. Geef de voorkeur aan asynchrone samenstelling in de gebruikersinterface en aanvraagthreads.

Een asynchrone werkstroom beschikbaar maken als een taak

Als u de bovenstaande werkstroom voor het lezen van bestanden wilt aanbieden aan bellers op basis van taken, accepteert u een annuleringstoken en geeft u het door Task.startAsyncImmediate:

let tryReadFileTask (path: string) (ct: CancellationToken) =
    tryReadFile path |> Task.startAsyncImmediate ct

De brug keert Task<string option> terug en geeft annulering door. Het begint op de aanroepende thread tot de eerste schorsing; latere vervolgen hoeven die thread niet te gebruiken.

Afhankelijke gelijktijdigheid

Een Async<'T> waarde beschrijft uitgestelde werkzaamheden. Een taak vertegenwoordigt meestal een bewerking die al is gestart. Als u het gebruik van resources wilt beperken, beschrijft u taakwerk als factory's in plaats van taken die al worden uitgevoerd:

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 begint bij de meeste positieve limiet van berekeningen gelijktijdig en retourneert resultaten in invoervolgorde. Beginvolgorde en voltooiingsorder zijn anders niet opgegeven. Voor gelijktijdigheid die groter is dan één, ontvangt elke fabriek een gekoppeld token dat ook een fout op hetzelfde niveau aangeeft; voor sequentiële uitvoering wordt het opgegeven token rechtstreeks ontvangen.

Wanneer één rekenfout optreedt, wordt annulering aangevraagd voor de broers en zussen. Bewerkingen moeten hun tokens observeren om samen te werken. Als verschillende berekeningen mislukken, wordt één uitzondering doorgegeven; is niet afhankelijk van welke fout wint.

Function Handtekeningshape
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>

De Async functies stromen het token voor omgevingsannulatie van de werkstroom. Bestaande Async.Parallel (inclusief de optie voor gelijktijdigheidslimiet) en Async.Sequential blijven beschikbaar. De Do varianten geven een unit resultaat weer wanneer u alleen voltooiing nodig hebt. Een gelijktijdigheidslimiet is geen frequentielimiet: snelle bewerkingen kunnen nog steeds veel aanvragen per seconde produceren.

Resultaten transformeren en herstellen van fouten

De Microsoft.FSharp.Control.Asyncmodules , Tasken ValueTask modules maken deze gekwalificeerde functies beschikbaar. M<'T> in de shapekolom staat voor het bijbehorende rekentype, geen F#-typeafkorting.

Gekwalificeerde functies Vorm
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>; expliciet invoertypeargument vereist.
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>

Wijs bijvoorbeeld de inhoud van een bestand toe aan een lengte en vertegenwoordig een leesfout als:Result

open System.IO
open System.Threading

let fileLength (path: string) (ct: CancellationToken) =
    File.ReadAllTextAsync(path, ct)
    |> Task.map String.length
    |> Task.catch

Een bestand dat een bestand bevat Report 1Ok 8. Een ontbrekend bestand bevat Error een FileNotFoundException. Als u een geslaagde waarde wilt negeren in plaats van deze te transformeren, geeft u het invoertype op wanneer u aanroept ignore:

let completion: System.Threading.Tasks.Task<unit> =
    Task.result 42 |> Task.ignore<int>

catchWith levert een vervangingswaarde op voor een niet-annuleringsfout; Er wordt geen andere asynchrone berekening uitgevoerd. catch retourneert Ok of Error. Annulering wordt niet geconverteerd naar een foutwaarde of doorgegeven aan de herstelhandler. Task.empty is een Task<unit>, niet de niet-generieke Task.CompletedTask.

In tegenstelling tot kleine letters Async.catch, bestaande Async.Catch retourneert Choice. Herstel verwerkt fouten van de opgegeven berekening, niet synchrone uitzonderingen die zijn gegenereerd vóór de aanroep. Async blijft uitgesteld; taken blijven gretig.

Beschikbaarheid van ValueTask en bibliotheek

ValueTask-API's vereisen de netstandard2.1 of net10.0 build van FSharp.Core 11. Zie Kerndoelselectie.

Bekijk het ValueTask-contract voor één verbruik: verbruik elke waarde één keer, niet via afzonderlijke wachten of pijplijnen. Voor herhaalde wachten roept Task.ofValueTask u één keer aan en gebruikt u alleen de resulterende taak.

Zie ook