简体   繁体   English

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

[英]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) AFAIK(例如这个博客文章 )异常不应该通过Async.Start冒泡(渲染try ... with没有意义,但是它存在于第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). (令人惊讶的)抛出代码被try ... with包围,但异常未被捕获(它永远不会打印"Failed" ,同样,应用程序崩溃)。

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. 所以,是的,这意味着异常不会传播到运行Async.Start的线程,并且永远不会命中try-with块。 But also, it means that the exception is now thrown elsewhere, and without any exception handling it will crash your app. 而且,这意味着异常现在被抛到其他地方,并且没有任何异常处理它将使您的应用程序崩溃。

Quoting MSDN : 引用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. 由于调用了Thread.Abort因此在线程池线程中抛出System.Threading.ThreadAbortException
  • A System.AppDomainUnloadedException is thrown in a thread pool thread because the application domain is being unloaded. 由于正在卸载应用程序域,因此在线程池线程中抛出System.AppDomainUnloadedException
  • 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. 使用Async.Start执行时, try无法在async捕获异常,因为它们分叉在不同的线程中。 If you want to catch it you can do so with Async.RunSynchronously or within another async : 如果要捕获它,可以使用Async.RunSynchronously或在另一个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!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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