Running this code:
open System
async {
printfn "a"
do!
Async.Parallel [|
Async.FromContinuations ignore // Sleep forever
async { return raise (Exception("Kaboom")) }
|]
|> Async.Ignore<unit array>
printfn "b"
}
|> Async.RunSynchronously
Gives this output:
a
printfn "b"
is never reached and the program appears to hang.
Why is this?
Shouldn't the exception cause the program to crash?
1 Answer 1
The behavior you're observing is due to how Async.Parallel
and Async.FromContinuations
work together in F#
Async.FromContinuations
:The ignore
function you passed to Async.FromContinuations
effectively ignores the continuations, meaning it never completes or raises an exception.
Async.Parallel
: This function runs multiple asynchronous workflows in parallel and waits for all of them to complete. The key word here is "Waits for all". If any of the workflows raise an exception,Async.Parallel
will propagate the exception.
Since Async.FromContinuations ignore
never completes, Async.Parallel
waits indefinitely for it to finish. This causes the entire asynchronous workflow to hang, and printfn "b"
is never reached.
So the only way to fix this is by ensuring that all workflows in Async.Parallel
can complete or handle exceptions properly. Something like below:
open System
async {
printfn "a"
try
do!
Async.Parallel [|
async {
// Simulate some work
do! Async.Sleep 1000
}
async {
return raise (Exception("Kaboom"))
}
|]
|> Async.Ignore<unit array>
with
| ex -> printfn "Exception: %s" ex.Message
printfn "b"
}
|> Async.RunSynchronously
The first workflow simulates some work with Async.Sleep
, ensuring it completes. The second workflow raises an exception, which is caught by the try...with
block, allowing the program to handle the exception and continue to printfn "b"
. Hope it helps
Async.FromContinuations ignore
is intended to be an async that sleeps forever - perhaps this is a bad implemenation? Should it sleep until cancellation is triggered?Async.Sleep
for an infinite time