How to correctly block on async code?
You do not correctly block on async code. Blocking is wrong. Asking what the right way is to do the wrong thing is a non-starter.
Blocking on async code is wrong because of the following scenario:
- I have an object in hand representing an async operation.
- The async operation is itself asynchronously waiting on the completion of a second async operation.
- The second async operation will be scheduled to this thread when the message loop executes code associated with a message that is at present in this thread's message queue.
And now you can figure out what goes horribly wrong when you attempt to fetch the result synchronously of the first async operation. It blocks until its child async operation is finished, which will never happen, because now we've blocked the thread that is going to service the request in the future!
Your choices are:
- Make your entire call stack correctly asynchronous and
await
the result.
- Don't use this API. Write an equivalent synchronous API that you know does not deadlock, from scratch, and call it correctly.
- Write an incorrect program which sometimes deadlocks unpredictably.
There are two ways to write a correct program; writing a synchronous wrapper over an asynchronous function is dangerous and wrong.
Now, you might ask, didn't the ConfigureAwait
solve the problem by removing the requirement that we resume on the current context? That's not the resumption point that we're worried about. If you're going to rely on ConfigureAwait
to save you from deadlock then every asynchronous operation in the stack has to use it, and we don't know if the underlying asynchronous operation that is about to cause the deadlock did that!
If the above is not entirely clear to you, read Stephen's article on why this is a bad practice, and why common workarounds are just dangerous hacks.
https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
and his updated article giving more hacks and workarounds here:
https://msdn.microsoft.com/en-us/magazine/mt238404.aspx?f=255&MSPPError=-2147217396
But again: the right thing to do is to redesign your program to embrace asynchrony and use await
throughout. Don't try to work around it.
becuase this method has stacktrace of ~20 methods, some of them are implementing some interfaces. Changing it to be async require change declarations in ~50 files, and we convert fully sync interfaces to mixed ones.
Get busy then! This sounds pretty easy.