F# Async
Async expressions
Async expressions provide one way of performing computations asynchronously, that is, without blocking execution of other work.
Asynchronous Binding by Using let!
The effect of let! is to enable execution to continue on other computations or threads as the computation is being performed. After the right side of the let! binding returns, the rest of the async expression resumes execution.
// 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!
can only be used to await F# async computations Async<T>
directly. You can await other kinds of asynchronous operations indirectly:
- .NET tasks,
Task<TResult>
and the non-generic Task, by combining withAsync.AwaitTask
- .NET value tasks,
ValueTask<TResult>
and the non-generic ValueTask, by combining with.AsTask()
andAsync.AwaitTask
- Any object following the “GetAwaiter” pattern specified in F# RFC FS-1097, by combining with
task { return! expr } |> Async.AwaitTask
.
use and use! bindings
In addition to let!
, you can use use! to perform asynchronous bindings. The difference between let! and use! is the same as the difference between let
and use
. For use!,
the object is disposed of at the close of the current scope. Note that in the current release of F#, use!
does not allow a value to be initialized to null, even though use does.
Asynchronous Primitives
A method that performs a single asynchronous task and returns the result is called an asynchronous primitive, and these are designed specifically for use with let!. Several asynchronous primitives are defined in the F# core library.
You use the function Async.RunSynchronously
to execute an asynchronous operation and wait for its result. As an example, you can execute multiple asynchronous operations in parallel by using the Async.Parallel function together with the Async.RunSynchronously
function. The Async.Parallel
function takes a list of the Async objects, sets up the code for each Async task object to run in parallel, and returns an Async object that represents the parallel computation. Just as for a single operation, you call Async.RunSynchronously
to start the execution.
open System.Net
open Microsoft.FSharp.Control.WebExtensions
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 webClient = new WebClient()
let! html = webClient.AsyncDownloadString(uri)
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()