考虑此控制台应用程序:
let throwAsync =
async { failwith "" }
[<EntryPoint>]
let main argv =
try Async.Start throwAsync
with _ -> printfn "Failed"
System.Console.Read() |> ignore
0
该应用在运行时立即崩溃。这对我来说没有任何意义,原因有两个:
Async.Start
冒出(使try ... with
毫无意义,但在第二点就可以了)try ... with
包围,但是没有捕获到异常(它永远不会打印"Failed"
,并且应用程序再次崩溃)。这是怎么回事?
答案 0 :(得分:4)
在执行异步块的线程池线程上引发异常。
是的,这意味着该异常不会传播到运行Async.Start
的线程,并且永远不会命中try-with
块。但是,这也意味着该异常现在已被抛出到其他地方,并且没有任何异常处理将导致您的应用程序崩溃。
引用MSDN:
线程池线程中未处理的异常会终止进程。此规则有三个例外:
- 因为调用了
System.Threading.ThreadAbortException
,所以在线程池线程中抛出了Thread.Abort
。- 由于正在卸载应用程序域,因此在线程池线程中引发了
System.AppDomainUnloadedException
。- 公共语言运行时或宿主进程终止线程。
有关更多信息,请参见Exceptions in Managed Threads。
答案 1 :(得分:1)
用try
执行时,async
无法捕获Async.Start
中的异常,因为它们分叉在不同的线程中。如果您想捕获它,可以使用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
输出:
caught outside!
caught inside async!
finishing!