Aszinkron és feladatfüggvények

Az FSharp.Core 11 függvényeket ad hozzá a feladatközi feladatokhoz, az eredményátalakításokhoz és a kötött egyidejűséghez. Használja őket meglévő aszinkron munkafolyamatokkal és feladatkifejezésekkel; nem igényelnek futtatókörnyezet-aszinkron prototípust.

Várakozás .NET műveletekre az aszinkrontól

Ha .NET műveletet szeretne elindítani az aszinkron munkafolyamat lemondási jogkivonatával, adjon át egy gyárat a következőnekAsync.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
    }

A fájlolvasás megkapja a munkafolyamat lemondási jogkivonatát. Egy hiányzó fájl ad Nonevissza; a sikeres olvasás eredménye Some contents. A munkafolyamat a befejezésre vár, beleértve a lemondást és a törlést is.

Akkor használja Async.Await , ha már rendelkezik feladathoz hasonló értékkel. Mindkét API közvetlenül propagálja a hibás tevékenységek egyetlen mögöttes kivételét. A több belső kivételt tartalmazó összesítés továbbra is összesítés marad. Async.AwaitTask megtartja a meglévő kivételburkoló viselkedését.

API Támogatott argumentum-/eredményalakzatok
Async.Await Task<'T> -> Async<'T>; Task -> Async<unit>
Async.Await ValueTask<'T> -> Async<'T>; ValueTask -> Async<unit>
Async.Await Beágyazott feladatszerű túlterhelés a GetAwaiter protokoll használatával.
Async.StartTaskImmediate (CancellationToken -> Task<'T>) -> Async<'T>; nem általános Task visszatérések Async<unit>.
Async.StartTaskImmediate Megfelelő ValueTask, ValueTask<'T>és feladatszerű gyári túlterhelések.
Task.startAsyncImmediate CancellationToken -> Async<'T> -> Task<'T>
Async.RunSynchronouslyImmediate Async<'T> * ?cancellationToken: CancellationToken -> 'T

Async.RunSynchronouslyImmediate a hívószálon indul el, ellentétben Async.RunSynchronously az előtérszállal, és befejező blokkokat ad meg. Nincs időtúllépési paramétere. A felhasználói felületen az aszinkron kompozíciót részesíti előnyben, és kérje le a szálakat.

Aszinkron munkafolyamat elérhetővé tétele feladatként

A fenti fájlolvasási munkafolyamat feladatalapú hívóknak való felajánlásához fogadja el a lemondási jogkivonatot, és adja át Task.startAsyncImmediate:

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

A híd visszaadja Task<string option> és propagálja a lemondást. Az első felfüggesztésig a hívó szálon kezdődik; a későbbi folytatásoknak nem kell ezt a szálat használniuk.

Kötött egyidejűség

Egy Async<'T> érték a késleltetett munkát írja le. A tevékenységek általában egy már elindított műveletet jelölnek. Az erőforrás-használat korlátozásához írja le a feladatokat gyárakként, nem pedig már futó tevékenységekként:

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 legfeljebb a számítások pozitív korlátját indítja el egyidejűleg, és bemeneti sorrendben adja vissza az eredményeket. A kezdő rendelés és a befejezési sorrend egyébként nincs meghatározva. Az egynél nagyobb egyidejűség esetén minden gyár kap egy csatolt jogkivonatot, amely a testvérhibát is jelzi; szekvenciális végrehajtás esetén közvetlenül megkapja a megadott jogkivonatot.

Ha egy számítási hiba történik, a rendszer lemondást kér a testvéreitől. A műveleteknek meg kell figyelniük a jogkivonataikat az együttműködéshez. Ha több számítás sikertelen, a rendszer egy kivételt propagált; nem függ attól, hogy melyik hiba nyer.

Function Aláírás alakzat
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>

A Async függvények a munkafolyamat környezeti lemondási jogkivonatát használják. Meglévő Async.Parallel (beleértve az egyidejűségi korlátot is) és Async.Sequential továbbra is elérhető marad. A Do változatok akkor teszik közzé az unit eredményt, ha csak befejezésre van szüksége. Az egyidejűségi korlát nem sebességkorlátozó: a gyors műveletek másodpercenként még mindig sok kérést eredményezhetnek.

Eredmények átalakítása és helyreállítás a hibákból

A Microsoft.FSharp.Control.Async, Taskés ValueTask a modulok elérhetővé teszik ezeket a minősített függvényeket. M<'T> az alakzatoszlop a megfelelő számítási típust jelöli, nem pedig az F# típusú rövidítést.

Minősített függvények Forma
\, \, \ 'T -> M<'T>
\, \, \ ('T -> 'U) -> M<'T> -> M<'U>
\, \, \ ('T -> M<'U>) -> M<'T> -> M<'U>
\, \, \ M<'T> -> M<unit>; explicit bemeneti típusú argumentum szükséges.
\, \, \ (exn -> 'T) -> M<'T> -> M<'T>
\, \, \ M<'T> -> M<Result<'T, exn>>
\, \, \ M<unit>
Task.ofValueTask ValueTask<'T> -> Task<'T>
ValueTask.ofTask Task<'T> -> ValueTask<'T>

Egy fájl tartalmának leképezése például hosszra, majd olvasási hiba:Result

open System.IO
open System.Threading

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

Az adást Ok 8tartalmazó Report 1 fájl. Egy hiányzó fájl Error egy FileNotFoundException. Ha nem átalakítja, hanem elvet egy sikeres értéket, adja meg a bemeneti típust a híváskor ignore:

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

catchWith csereértéket biztosít a nem lemondási hiba esetén; nem futtat újabb aszinkron számítást. catch visszaadja vagy OkError. A rendszer nem konvertálja a lemondást hibaértékké, és nem továbbítja a helyreállítási kezelőnek. Task.empty Task<unit>a , nem a nem általános Task.CompletedTask.

A kisbetűstől Async.catcheltérően a meglévő Async.Catch eredmény.Choice A recovery a megadott számítás hibáit kezeli, nem pedig a hívás előtt kidobott szinkron kivételeket. Az Async halasztva marad; feladatok továbbra is lelkesek maradnak.

ValueTask és könyvtár rendelkezésre állása

A ValueTask API-k megkövetelik az netstandard2.1 FSharp.Core 11-et vagy net10.0 buildet. Lásd : Alapvető cél kiválasztása.

Figyelje meg az egyszerhasználatos ValueTask-szerződést: az egyes értékeket egyszer használja fel, nem pedig külön várakozásokon vagy folyamatokon keresztül. Ismétlődő várakozások esetén hívja Task.ofValueTask meg egyszer, és csak az eredményül kapott feladatot használja újra.

Lásd még