Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Tento článek popisuje podporu v jazyce F# pro asynchronní výrazy. Asynchronní výrazy poskytují jeden způsob asynchronního provádění výpočtů, tj. bez blokování provádění jiné práce. Například asynchronní výpočty se dají použít k psaní aplikací, které mají uživatelská rozhraní, která reagují na uživatele, když aplikace provádí jinou práci. Programovací model asynchronních pracovních postupů jazyka F# umožňuje psát funkční programy při skrytí podrobností přechodu vlákna v knihovně.
Asynchronní kód lze také vytvořit pomocí výrazů úloh, které vytvářejí úlohy .NET přímo. Použití výrazů úloh se upřednostňuje při rozsáhlé spolupráci s knihovnami .NET, které vytvářejí nebo využívají úlohy .NET. Při psaní většiny asynchronního kódu v jazyce F# jsou upřednostňované asynchronní výrazy jazyka F#, protože jsou stručnější, kompozitivnější a vyhněte se určitým upozorněním spojeným s úlohami .NET.
Syntaxe
async { expression }
Poznámky
V předchozí syntaxi je výpočet reprezentovaný expression tak, aby běžel asynchronně, tj. bez blokování aktuálního výpočtu vlákna při asynchronních operacích spánku, vstupně-výstupních operací a dalších asynchronních operacích. Typ výrazu je Async<'T>, kde 'T je typ vrácený výrazem při použití klíčového return slova.
Třída Async poskytuje metody, které podporují několik scénářů. Obecný přístup spočívá v vytváření Async objektů, které představují výpočty nebo výpočty, které chcete spustit asynchronně, a pak tyto výpočty spustit pomocí jedné z aktivačních funkcí. Aktivace, kterou použijete, závisí na tom, jestli chcete použít aktuální vlákno, vlákno na pozadí nebo objekt úlohy .NET. Chcete-li například spustit asynchronní výpočty v aktuálním vlákně, můžete použít Async.StartImmediate. Když spustíte asynchronní výpočet z vlákna uživatelského rozhraní, nezablokujete hlavní smyčku událostí, která zpracovává akce uživatele, jako jsou stisknutí kláves a aktivita myši, takže vaše aplikace zůstane responzivní.
Asynchronní vazba pomocí let!
V asynchronním výrazu jsou některé výrazy a operace synchronní a některé jsou asynchronní. Při asynchronním volání metody namísto obyčejné let vazby použijete let!. Vliv let! umožňuje, aby provádění pokračovalo na jiných výpočtech nebo vláknech, zatímco je provádění výpočtu realizováno. Jakmile se vrátí pravá strana let! vazby, zbytek asynchronního výrazu obnoví provádění.
Následující kód ukazuje rozdíl mezi let a let!. Řádek kódu, který používá let pouze vytvoří asynchronní výpočet jako objekt, který můžete spustit později pomocí, například Async.StartImmediate nebo Async.RunSynchronously. Řádek kódu, který používá let! spuštění výpočtu a provádí asynchronní čekání: vlákno je pozastaveno, dokud nebude k dispozici výsledek, v jakém okamžiku bude provádění pokračovat.
// let just stores the result as an asynchronous operation.
let (result1 : Async<byte[]>) = stream.AsyncRead(bufferSize)
// let! completes the asynchronous operation and returns the data.
let! (result2 : byte[]) = stream.AsyncRead(bufferSize)
let! lze použít pouze k přímému čekání asynchronních výpočtů jazyka Async<T> F#. Můžete očekávat další druhy asynchronních operací nepřímo:
- Úlohy .NET a negenerické Task<TResult>úlohy Task pomocí kombinace
Async.AwaitTask - Úlohy hodnot .NET a ne generické ValueTask<TResult>, ValueTask kombinováním a
.AsTask()Async.AwaitTask - Libovolný objekt, který následuje za vzorem GetAwaiter zadaným v F# RFC FS-1097, zkombinováním s
task { return! expr } |> Async.AwaitTask.
Řízení toku
Asynchronní výrazy mohou zahrnovat konstrukty toku řízení, jako for .. in .. dojsou , while .. do, try .. with .., try .. finally .., , if .. then .. elsea if .. then ... Ty pak mohou zahrnovat další asynchronní konstrukce s výjimkou with obslužných finally rutin, které se provádějí synchronně.
Asynchronní výrazy jazyka F# nepodporují asynchronní try .. finally ..výrazy . V tomto případě můžete použít výraz úkolu .
use a use! vazby
V rámci asynchronních výrazů mohou vazby use svázat s hodnotami typu IDisposable. U druhé možnosti se operace odstranění provádí asynchronně.
Kromě let! toho můžete provádět asynchronní vazby pomocí use!. Rozdíl mezi let! a use! je stejný jako rozdíl mezi let a use. Pro use!, objekt je s uzavřením aktuálního oboru uvolněn. Všimněte si, use! že v aktuální verzi jazyka F# neumožňuje inicializaci hodnoty na hodnotu null, i když use ano.
Asynchronní primitivy
Metoda, která provádí jednu asynchronní úlohu a vrací výsledek, se nazývá asynchronní primitiva, a jsou navrženy speciálně pro použití s let!. V základní knihovně jazyka F# je definováno několik asynchronních primitiv. V modulu FSharp.Control.WebExtensionsjsou definovány dvě takové metody pro webové aplikace : WebRequest.AsyncGetResponse a HttpClient.GetStringAsync (zabalené z důvodu kompatibility s asynchronním modelem Async.AwaitTask jazyka F#). Obě primitiva stahují data z webové stránky s adresou URL.
AsyncGetResponse
System.Net.WebResponse vytvoří objekt a GetStringAsync vytvoří řetězec, který představuje html pro webovou stránku.
Modul obsahuje FSharp.Control.CommonExtensions několik primitiv pro asynchronní vstupně-výstupní operace. Tyto rozšiřující metody System.IO.Stream třídy jsou Stream.AsyncRead a Stream.AsyncWrite.
Můžete také napsat vlastní asynchronní primitivy definováním funkce nebo metody, jejíž tělo je asynchronní výraz.
Pokud chcete použít asynchronní metody v rozhraní .NET Framework, které jsou navržené pro jiné asynchronní modely s asynchronním programovacím modelem jazyka F#, vytvoříte funkci, která vrátí objekt F# Async . Knihovna jazyka F# má funkce, které usnadňují práci.
Tady je uveden jeden příklad použití asynchronních výrazů; v dokumentaci k metodám třídy Async existuje mnoho dalších.
Tento příklad ukazuje, jak paralelně spouštět kód pomocí asynchronních výrazů.
V následujícím příkladu kódu získá funkce fetchAsync text HTML vrácený z webového požadavku. Funkce fetchAsync obsahuje asynchronní blok kódu. Při vytvoření vazby na výsledek asynchronní primitiv, v tomto případě AsyncDownloadStringse let! použije místo let.
Pomocí funkce Async.RunSynchronously spustíte asynchronní operaci a počkáte na její výsledek. Jako příklad můžete paralelně spouštět více asynchronních operací pomocí Async.Parallel funkce společně s Async.RunSynchronously funkcí. Funkce Async.Parallel vezme seznam Async objektů, nastaví kód pro každý Async objekt úkolu, který se spustí paralelně, a vrátí Async objekt, který představuje paralelní výpočty. Stejně jako u jedné operace voláte Async.RunSynchronously , aby se spustilo spuštění.
Funkce runAll spustí paralelně tři asynchronní výrazy a počká, dokud se nedokončí.
open System.Net
open Microsoft.FSharp.Control.WebExtensions
open System.Net.Http
let urlList = [ "Microsoft.com", "http://www.microsoft.com/"
"MSDN", "http://msdn.microsoft.com/"
"Bing", "http://www.bing.com"
]
let fetchAsync(name, url:string) =
async {
try
let uri = new System.Uri(url)
let httpClient = new HttpClient()
let! html = httpClient.GetStringAsync(uri) |> Async.AwaitTask
printfn "Read %d characters for %s" html.Length name
with
| ex -> printfn "%s" (ex.Message);
}
let runAll() =
urlList
|> Seq.map fetchAsync
|> Async.Parallel
|> Async.RunSynchronously
|> ignore
runAll()