Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Język FSharp.Core 11 dodaje funkcje międzyoperacyjności zadań, przekształceń wyników i powiązanej współbieżności. Używaj ich z istniejącymi przepływami pracy asynchronicznych i wyrażeniami zadań; nie wymagają prototypu asynchronicznego środowiska uruchomieniowego.
Oczekiwanie na operacje .NET z poziomu asynchronicznego
Aby rozpocząć operację .NET z tokenem anulowania przepływu pracy asynchronicznego, przekaż fabrykę do :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
}
Odczyt pliku odbiera token anulowania przepływu pracy. Brakujący plik zwraca wartość None; pomyślny odczyt zwraca wartość Some contents. Przepływ pracy czeka na ukończenie, w tym anulowanie i oczyszczanie.
Użyj Async.Await polecenia , jeśli masz już wartość podobną do zadania. Oba interfejsy API propagują pojedynczy podstawowy wyjątek bezpośrednio uszkodzonego zadania. Agregacja z wieloma wyjątkami wewnętrznymi pozostaje agregacja.
Async.AwaitTask zachowuje istniejące zachowanie opakowujące wyjątki.
| API | Obsługiwane kształty argumentów/wyników |
|---|---|
Async.Await |
Task<'T> -> Async<'T>; Task -> Async<unit> |
Async.Await |
ValueTask<'T> -> Async<'T>; ValueTask -> Async<unit> |
Async.Await |
Wbudowane przeciążenie przypominające zadanie przy użyciu GetAwaiter protokołu. |
Async.StartTaskImmediate |
(CancellationToken -> Task<'T>) -> Async<'T>; funkcja niegeneryczna Task zwraca wartość Async<unit>. |
Async.StartTaskImmediate |
Odpowiadające ValueTaskprzeciążenia fabryki , , ValueTask<'T>i podobne do zadań. |
Task.startAsyncImmediate |
CancellationToken -> Async<'T> -> Task<'T> |
Async.RunSynchronouslyImmediate |
Async<'T> * ?cancellationToken: CancellationToken -> 'T |
Async.RunSynchronouslyImmediate rozpoczyna się od wątku wywołującego, w przeciwieństwie do Async.RunSynchronously wątku pierwszego planu i bloków na potrzeby ukończenia. Nie ma parametru limitu czasu. Preferuj asynchroniczną kompozycję interfejsu użytkownika i żądaj wątków.
Uwidacznianie asynchronicznego przepływu pracy jako zadania
Aby zaoferować powyższy przepływ pracy odczytu plików obiektom wywołującym opartym na zadaniach, zaakceptuj token anulowania i przekaż go za pośrednictwem polecenia Task.startAsyncImmediate:
let tryReadFileTask (path: string) (ct: CancellationToken) =
tryReadFile path |> Task.startAsyncImmediate ct
Mostek zwraca Task<string option> i propaguje anulowanie. Rozpoczyna się na wątek wywołujący do pierwszego zawieszenia; późniejsze kontynuacje nie muszą używać tego wątku.
Powiązana współbieżność
Wartość Async<'T> opisuje odroczone prace. Zadanie zwykle reprezentuje operację, która została już uruchomiona. Aby ograniczyć użycie zasobów, opisz pracę zadania jako fabryki, a nie już uruchomione zadania:
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 rozpoczyna się co najwyżej dodatni limit obliczeń jednocześnie i zwraca wyniki w kolejności danych wejściowych. Kolejność rozpoczęcia i kolejność ukończenia są w przeciwnym razie nieokreślone. W przypadku współbieżności większej niż jednej każda fabryka otrzymuje połączony token, który również sygnalizuje awarię elementu równorzędnego; w przypadku wykonywania sekwencyjnego otrzymuje podany token bezpośrednio.
W przypadku wystąpienia jednego błędu obliczeniowego żądanie anulowania jest wymagane dla jego elementów równorzędnych. Operacje muszą obserwować swoje tokeny do współpracy. Jeśli kilka obliczeń nie powiedzie się, jeden wyjątek jest propagowany; nie zależy od tego, która awaria zostanie wygrana.
| Function | Kształt podpisu |
|---|---|
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> |
Funkcje Async przepływają token anulowania otoczenia przepływu pracy. Istniejące Async.Parallel (w tym opcja limitu współbieżności) i Async.Sequential pozostają dostępne. Warianty Do uwidaczniają unit wynik tylko wtedy, gdy potrzebujesz tylko ukończenia. Limit współbieżności nie jest ograniczeniem szybkości: szybkie operacje mogą nadal generować wiele żądań na sekundę.
Przekształcanie wyników i odzyskiwanie po błędach
Moduły Microsoft.FSharp.Control.Async, Taski ValueTask uwidaczniają te kwalifikowane funkcje.
M<'T> w kolumnie kształtu oznacza odpowiedni typ obliczeniowy, a nie skrót typu F#.
| Kwalifikowane funkcje | 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>; wymagany jest jawny argument typu wejściowego. |
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> |
Na przykład zamapuj zawartość pliku na długość, a następnie reprezentuje błąd odczytu jako :Result
open System.IO
open System.Threading
let fileLength (path: string) (ct: CancellationToken) =
File.ReadAllTextAsync(path, ct)
|> Task.map String.length
|> Task.catch
Plik zawierający Report 1 polecenie daje Ok 8. Brakujący plik zawiera element ErrorFileNotFoundException. Aby odrzucić pomyślną wartość, a nie przekształcić ją, określ typ danych wejściowych podczas wywoływania elementu ignore:
let completion: System.Threading.Tasks.Task<unit> =
Task.result 42 |> Task.ignore<int>
catchWith dostarcza wartość zastępczą dla niepowodzenia nieuwołania; nie uruchamia innego obliczenia asynchronicznego.
catch zwraca wartość Ok lub Error. Anulowanie nie jest konwertowane na wartość błędu ani przekazywane do procedury obsługi odzyskiwania.
Task.empty jest elementem , a Task<unit>nie ogólnym Task.CompletedTask.
W przeciwieństwie do małych liter istniejąca Async.catchAsync.Catch zwraca wartość Choice. Odzyskiwanie obsługuje błędy dostarczonego obliczenia, a nie wyjątki synchroniczne zgłaszane przed wywołaniem. Asynchronizuj pozostaje odroczony; zadania pozostają chętne.
ValueTask i dostępność biblioteki
Interfejsy API valueTask wymagają netstandard2.1 kompilacji FSharp.Core 11 lub net10.0 . Zobacz Wybór miejsca docelowego rdzenia.
Obserwuj kontrakt ValueTask z pojedynczym użyciem: zużywaj każdą wartość raz, a nie przez oddzielne oczekiwania lub potoki. W przypadku powtórzeń czekaj wywołaj Task.ofValueTask raz i ponownie użyj tylko wynikowego zadania.