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:
Async.Start
(rendering the try ... with
pointless, but it's there for point 2)try ... with
, but the exception is not caught (it never prints "Failed"
, and again, the app crashes).What's going on?
An asynchronous exception is uncatchable because the intended catch block is not present when the asynchronous callback is executed. Instead, the exception will propagate all the way and terminate the program. Does taking a callback make a function asynchronous?
With async void methods, there is no Task object, so any exceptions thrown out of an async void method will be raised directly on the SynchronizationContext that was active when the async void method started. Figure 2 illustrates that exceptions thrown from async void methods can’t be caught naturally.
If you do not await, any exceptions that occur in the calling method will be swallowed. Essentially you are turning the method call into a fire and forget. Below is a simple example that demonstrates two behaviors of calling await on an async. To run the example, just copy and paste in a new console application.
Event handlers naturally return void, so async methods return void so that you can have an asynchronous event handler. However, some semantics of an async void method are subtly different than the semantics of an async Task or async Task<T> method.
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 becauseThread.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With