Asynkronisering och aktivitetsfunktioner

FSharp.Core 11 lägger till funktioner för aktivitetssammansättning, resultattransformeringar och begränsad samtidighet. Använd dem med befintliga asynkrona arbetsflöden och uppgiftsuttryck. de kräver inte prototypen runtime-async.

Vänta på .NET åtgärder från asynkronisering

Om du vill starta en .NET åtgärd med asynkrona arbetsflödets annulleringstoken skickar du en fabrik till 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
    }

Filläsningen tar emot arbetsflödets annulleringstoken. En fil som saknas returnerar None; en lyckad läsning returnerar Some contents. Arbetsflödet väntar på slutförande, inklusive annullering och rensning.

Använd Async.Await när du redan har ett aktivitetsliknande värde. Båda API:erna sprider det enda underliggande undantaget för en felaktig uppgift direkt. En aggregering med flera inre undantag förblir en aggregering. Async.AwaitTask behåller sitt befintliga undantagshanteringsbeteende.

API Argument-/resultatformer som stöds
Async.Await Task<'T> -> Async<'T>; Task -> Async<unit>
Async.Await ValueTask<'T> -> Async<'T>; ValueTask -> Async<unit>
Async.Await Infogad uppgiftsliknande överlagring med hjälp av GetAwaiter protokollet.
Async.StartTaskImmediate (CancellationToken -> Task<'T>) -> Async<'T>; icke-generiska Task returnerar Async<unit>.
Async.StartTaskImmediate Motsvarande ValueTask, ValueTask<'T>och aktivitetsliknande fabriksöverlagringar.
Task.startAsyncImmediate CancellationToken -> Async<'T> -> Task<'T>
Async.RunSynchronouslyImmediate Async<'T> * ?cancellationToken: CancellationToken -> 'T

Async.RunSynchronouslyImmediate startar på den anropande tråden, till skillnad från Async.RunSynchronously på en förgrundstråd, och block för slutförande. Den har ingen timeout-parameter. Föredrar asynkron komposition i användargränssnittet och begärandetrådar.

Exponera ett asynkront arbetsflöde som en uppgift

Om du vill erbjuda arbetsflödet för filläsning ovan till uppgiftsbaserade anropare godkänner du en annulleringstoken och skickar den genom Task.startAsyncImmediate:

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

Bryggan returnerar Task<string option> och sprider annullering. Den startar på den anropande tråden tills den första fjädringen; senare fortsättningar behöver inte använda den tråden.

Bunden samtidighet

Ett Async<'T> värde beskriver uppskjutet arbete. En uppgift representerar vanligtvis en åtgärd som redan har startats. Om du vill begränsa resursanvändningen beskriver du aktivitetsarbete som fabriker i stället för aktiviteter som redan körs:

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 startar högst den positiva gränsen för beräkningar samtidigt och returnerar resultat i indataordning. Startordningen och slutförandeordningen är annars ospecificerade. För samtidighet som är större än en får varje fabrik en länkad token som också signalerar syskonfel. för sekventiell körning tar den emot den angivna token direkt.

När ett beräkningsfel uppstår begärs annullering för dess syskon. Åtgärderna måste observera sina token för att samarbeta. Om flera beräkningar misslyckas sprids ett undantag. beror inte på vilket fel som vinner.

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

Funktionerna Async flödar arbetsflödets omgivande annulleringstoken. Befintlig Async.Parallel (inklusive dess alternativ för samtidighetsgräns) och Async.Sequential förblir tillgänglig. Varianterna Do visar ett unit resultat när du bara behöver slutföras. En samtidighetsgräns är inte en hastighetsbegränsning: snabba åtgärder kan fortfarande generera många begäranden per sekund.

Transformera resultat och återställa från fel

Modulerna Microsoft.FSharp.Control.Async, Taskoch ValueTask exponerar dessa kvalificerade funktioner. M<'T> i formkolumnen står för motsvarande beräkningstyp, inte en F#-typförkortning.

Kvalificerade funktioner Form
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>; explicit argument för indatatyp som krävs.
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>

Mappa till exempel en fils innehåll till en längd och representera sedan ett läsfel som :Result

open System.IO
open System.Threading

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

En fil som innehåller Report 1 ger Ok 8. En fil som saknas ger en Error som innehåller en FileNotFoundException. Om du vill ignorera ett lyckat värde i stället för att transformera det anger du indatatypen när du anropar ignore:

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

catchWith tillhandahåller ett ersättningsvärde för ett icke-annulleringsfel. Den kör inte någon annan asynkron beräkning. catch returnerar Ok eller Error. Annullering konverteras inte till ett felvärde eller skickas till återställningshanteraren. Task.empty är en Task<unit>, inte den icke-generiska Task.CompletedTask.

Till skillnad från gemener Async.catchreturnerar befintliga Async.Catch .Choice Återställningen hanterar fel i den angivna beräkningen, inte synkrona undantag som utlöses före anropet. Async förblir uppskjuten. uppgifter är fortfarande ivriga.

ValueTask och bibliotekstillgänglighet

ValueTask-API:er kräver netstandard2.1 eller net10.0 bygger på FSharp.Core 11. Se Val av kärnmål.

Observera valueTask-kontraktet med enkel förbrukning: förbruka varje värde en gång, inte via separata inväntningar eller pipelines. Vid upprepade inväntningar anropar Task.ofValueTask du en gång och återanvänder endast den resulterande uppgiften.

Se även