Fungsi asinkron dan tugas

FSharp.Core 11 menambahkan fungsi untuk interop tugas, transformasi hasil, dan konkurensi terikat. Gunakan dengan alur kerja asinkron dan ekspresi tugas yang ada; mereka tidak memerlukan prototipe runtime-async.

Menunggu operasi .NET dari asinkron

Untuk memulai operasi .NET dengan token pembatalan alur kerja asinkron, teruskan pabrik ke 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
    }

File yang dibaca menerima token pembatalan alur kerja. File yang hilang mengembalikan None; bacaan yang berhasil mengembalikan Some contents. Alur kerja menunggu penyelesaian, termasuk pembatalan dan pembersihan.

Gunakan Async.Await saat Anda sudah memiliki nilai seperti tugas. Kedua API menyebarluaskan pengecualian tunggal yang mendasar dari tugas yang salah secara langsung. Agregat dengan beberapa pengecualian dalam tetap menjadi agregat. Async.AwaitTask menjaga perilaku pembungkusan pengecualian yang ada.

API Bentuk argumen/hasil yang didukung
Async.Await Task<'T> -> Async<'T>; Task -> Async<unit>
Async.Await ValueTask<'T> -> Async<'T>; ValueTask -> Async<unit>
Async.Await Beban berlebih GetAwaiter seperti tugas sebaris menggunakan protokol.
Async.StartTaskImmediate (CancellationToken -> Task<'T>) -> Async<'T>; non-generik Task mengembalikan Async<unit>.
Async.StartTaskImmediate ValueTaskPabrik yang sesuai , ValueTask<'T>, dan seperti tugas kelebihan beban.
Task.startAsyncImmediate CancellationToken -> Async<'T> -> Task<'T>
Async.RunSynchronouslyImmediate Async<'T> * ?cancellationToken: CancellationToken -> 'T

Async.RunSynchronouslyImmediate dimulai pada utas panggilan, tidak seperti Async.RunSynchronously pada utas latar depan, dan blok untuk penyelesaian. Ini tidak memiliki parameter batas waktu. Lebih suka komposisi asinkron pada UI dan minta utas.

Mengekspos alur kerja asinkron sebagai tugas

Untuk menawarkan alur kerja pembacaan file di atas kepada pemanggil berbasis tugas, terima token pembatalan dan berikan melalui Task.startAsyncImmediate:

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

Jembatan kembali Task<string option> dan menyebarluaskan pembatalan. Ini dimulai pada utas panggilan sampai penangguhan pertama; kelanjutan selanjutnya tidak perlu menggunakan utas tersebut.

Konkurensi terikat

Nilai Async<'T> menjelaskan pekerjaan yang ditangguhkan. Tugas biasanya mewakili operasi yang telah dimulai. Untuk membatasi penggunaan sumber daya, jelaskan tugas bekerja sebagai pabrik daripada tugas yang sudah berjalan:

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 dimulai paling banyak batas positif komputasi secara bersamaan dan mengembalikan hasil dalam urutan input. Urutan mulai dan urutan penyelesaian tidak ditentukan. Untuk konkurensi yang lebih besar dari satu, setiap pabrik menerima token tertaut yang juga menandakan kegagalan saudara; untuk eksekusi berurutan, ia menerima token yang disediakan secara langsung.

Ketika satu kesalahan komputasi, pembatalan diminta untuk saudara kandungnya. Operasi harus mengamati token mereka untuk bekerja sama. Jika beberapa komputasi gagal, satu pengecualian disebarluaskan; tidak bergantung pada kegagalan mana yang menang.

Function Bentuk tanda tangan
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>

Fungsi mengalir Async token pembatalan sekitar alur kerja. Async.Parallel Yang ada (termasuk opsi batas konkurensinya) dan Async.Sequential tetap tersedia. Varian Do mengekspos unit hasil ketika Anda hanya membutuhkan penyelesaian. Batas konkurensi bukan pembatas tarif: operasi cepat masih dapat menghasilkan banyak permintaan per detik.

Mengubah hasil dan memulihkan dari kesalahan

Modul Microsoft.FSharp.Control.Async, Task, dan ValueTask mengekspos fungsi yang memenuhi syarat ini. M<'T> di kolom bentuk adalah singkatan dari jenis komputasi yang sesuai, bukan singkatan jenis F#.

Fungsi yang memenuhi syarat Shape
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>; Argumen jenis input eksplisit diperlukan.
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>

Misalnya, petakan konten file ke panjang, lalu mewakili kegagalan baca sebagai Result:

open System.IO
open System.Threading

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

File yang berisi Report 1 memberikan Ok 8. File yang hilang memberikan yang Error berisi FileNotFoundException. Untuk membuang nilai yang berhasil daripada mengubahnya, tentukan jenis input saat Anda memanggil ignore:

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

catchWith memasok nilai pengganti untuk kegagalan non-pembatalan; tidak menjalankan komputasi asinkron lainnya. catch Ok mengembalikan atau Error. Pembatalan tidak dikonversi ke nilai kesalahan atau diteruskan ke handler pemulihan. Task.empty adalah Task<unit>, bukan yang non-generik Task.CompletedTask.

Tidak seperti huruf kecil Async.catch, pengembalian Async.Catch yang Choiceada . Pemulihan menangani kegagalan komputasi yang disediakan, bukan pengecualian sinkron yang dilemparkan sebelum panggilan. Asinkron tetap ditangguhkan; tugas tetap bersemangat.

Ketersediaan ValueTask dan pustaka

API ValueTask memerlukan netstandard2.1 atau net10.0 membangun FSharp.Core 11. Lihat Pemilihan target inti.

Amati kontrak konsumsi tunggal ValueTask: konsumsi setiap nilai sekali, bukan melalui menunggu atau alur terpisah. Untuk menunggu berulang, panggil Task.ofValueTask sekali dan gunakan kembali hanya tugas yang dihasilkan.

Baca juga