Async Workflows

Async is cold (nothing runs until started) and carries a cancellation token implicitly. Task is hot (starts immediately).

let fetchData (id: int) = async {
    do! Async.Sleep 500                       // non-blocking delay
    return $"data for {id}"
}

// Run one
fetchData 1 |> Async.RunSynchronously        // blocks; use only at the top level/scripts

// Run many in parallel
let all =
    [1 .. 5]
    |> List.map fetchData
    |> Async.Parallel                         // Async<string[]>
    |> Async.RunSynchronously

// Limit the degree of parallelism
let throttled = Async.Parallel([ for i in 1 .. 20 -> fetchData i ], maxDegreeOfParallelism = 4)

// Sequential
let seqResults = [1 .. 3] |> List.map fetchData |> Async.Sequential

// Fire-and-forget and background start
Async.Start (async { printfn "background" })
let child = async {
    let! started = Async.StartChild(fetchData 9, millisecondsTimeout = 2000)   // with a timeout
    return! started
}

// Cancellation (Async is cancellable by design)
let cts = new System.Threading.CancellationTokenSource()
let longRunning = async {
    for i in 1 .. 100 do
        do! Async.Sleep 100
        printfn "step %d" i
}
Async.Start(longRunning, cts.Token)
cts.CancelAfter 350

// Error handling
let safe = async {
    try
        let! r = async { return failwit
…