为什么 Async.Start 似乎会传播无法捕获的异常?

cme*_*ren 5 f# asynchronous exception async-await

考虑这个控制台应用程序:

let throwAsync = 
  async { failwith "" }

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

该应用程序运行时立即崩溃。这对我来说没有意义,原因有二:

  1. AFAIK(例如这篇博客文章)异常不应该冒泡Async.Start(使得try ... with毫无意义,但它存在于第 2 点)
  2. (令人惊讶地)抛出的代码被 包围try ... with,但异常没有被捕获(它从不打印"Failed",并且应用程序再次崩溃)。

这是怎么回事?

scr*_*wtp 5

异常在执行异步块的线程池线程上引发。

所以是的,这意味着异常不会传播到 run 的线程Async.Start,并且try-with块永远不会被命中。而且,这也意味着异常现在被抛出到其他地方,并且如果没有任何异常处理,它将使您的应用程序崩溃。

引用MSDN

线程池线程中未处理的异常会终止进程。此规则有以下三个例外:

  • ASystem.Threading.ThreadAbortException因为被调用而被抛出到线程池线程中Thread.Abort
  • System.AppDomainUnloadedException由于正在卸载应用程序域,因此在线程池线程中抛出A。
  • 公共语言运行时或主机进程终止线程。

有关详细信息,请参阅托管线程中的异常