简体   繁体   中英

Why does Async.Start seemingly propagate uncatchable exceptions?

Consider this console app:

let throwAsync = 
  async { failwith "" }

[<EntryPoint>]
let main argv =
  try Async.Start throwAsync
  with _ -> printfn "Failed"
  System.Console.Read() |> ignore
  0

The app crashes immediately when run. This doesn't make sense to me, for two reasons:

  1. AFAIK (eg this blog post ) exceptions should not bubble up through Async.Start (rendering the try ... with pointless, but it's there for point 2)
  2. The (surprisingly) throwing code is surrounded by try ... with , but the exception is not caught (it never prints "Failed" , and again, the app crashes).

What's going on?

The exception is thrown on a threadpool thread where the async block executes.

So yes, this means that the exception is not propagated to the thread that ran Async.Start , and the try-with block is never hit. But also, it means that the exception is now thrown elsewhere, and without any exception handling it will crash your app.

Quoting MSDN :

Unhandled exceptions in thread pool threads terminate the process. There are three exceptions to this rule:

  • A System.Threading.ThreadAbortException is thrown in a thread pool thread because Thread.Abort was called.
  • A System.AppDomainUnloadedException is thrown in a thread pool thread because the application domain is being unloaded.
  • The common language runtime or a host process terminates the thread.

For more information, see Exceptions in Managed Threads .

A try cannot catch an exception in an async when executed with Async.Start because they fork in different threads. If you want to catch it you can do so with Async.RunSynchronously or within another async :

let throwAsync = async { failwith "I was not caught!" }

let catchAsync = async {
    try 
        do! throwAsync
    with _-> printfn "caught inside async!"
}

[<EntryPoint>]
let main argv =
    try throwAsync |> Async.RunSynchronously 
    with _ -> printfn "caught outside!"
    try catchAsync |> Async.Start 
    with _ -> printfn "I did not catch it either!"
    System.Console.Read() |> ignore
    printfn "finishing!"
    0

output:

caught outside!
caught inside async!
finishing!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM