Best solution for asynchronous chicken and egg history

I am applying the best async techniques for all my libraries. This basically means:

  • Use async only when asynchronous (libraries shouldn't lie)
  • Define a synchronous method if and only if you have a faster synchronous method that won't block blocking.
  • Postfix all async methods with Async

I was working on a library that is synchronous in nature. This means that it only has sync methods. If the user wants to start work on a separate thread other than the UI thread, they can do it themselves using Task.Factory

(the responsibility of the caller).

However, inside the handler / method / extensibility point, we want to show the user a message box. This is an asynchronous method (like WinRT ShowDialogAsync

). This then gives us the following possibilities:

and. Move everything to async (so we have the option to use await in our handlers and not block anything).

public async Task MyMethodAsync()
    await _messageService.ShowAsync();


The advantage is that users can add asynchronous methods without using .Wait (). The downside is that we're lying as a library (it's not really asynchronous).

I thought everything was asynchronous, but I don't think that is a good idea either. This would make all the libraries lie, but prepare them if necessary. Remember, making everything asynchronous out of the box has a (small) performance impact.

B. Inside a handler that requires user input, call .Wait ()

public void MyMethod()


The advantage is that it allows us to use asynchronous code inside synchronization methods. But ... it will never be called from the UI thread because the _messageService dispatches the UI thread (but it cannot do that because it is still waiting for this method, which results in a deadlock). This method will work when used inside a Task.Factory.Run block (but the responsibility for it depends on the end user):

await Task.Factory.Run(() => MyMethod());



I feel like there are pros and cons to both, but which would you choose? Suppose the library lies (A) or only allows method calls from a background thread (B)? Or perhaps there are other options that I have observed.

If I go to A, it means that I have to hit the major version every time (because this is actually a violation) when the user asks to convert the method to an asynchronous signature method.


source to share

2 answers

Define a synchronous method if and only if you have a faster synchronous method that does not block.

I would say, "Define a synchronous method if you have synchronous work." It doesn't matter how fast it is. The burden lies with the caller to determine if it is too slow and they need to use Task.Run


However, inside the handler / method / extensibility point

If it's kind of Observer extensibility, consider only using events or observables.

However, it looks like you want more of Strategy's extensibility, where your caller must wait and / or change its behavior based on the result of the callback.

I've decided to make everything asynchronous, but I don't think that's a good idea either.

Async is a guideline, not a strict command. This definitely applies 99% of the time, but this may be one of the exceptions. I would try not to create an asynchronous library just for the sake of the asynchronous parsing strategy pattern; I first explored other extensibility options. There is a valid argument for making the library asynchronous if you treat the strategy callback as a dependency (the library will be asynchronous since its dependency is (possibly) async).

As you have found, there is no clean way to do sync-over-async. There are a few different hacks (like blocking from a background thread), but first you need to decide if you need to call your library from the UI thread.

If you do that, then there are only two options: make an asynchronous library or use a nested message loop. I strongly avoid nested message loops, especially in libraries; I am just mentioning this for the sake of completeness.

If you can force the user to only call the library from a non-UI thread, then you can apply other hacks. For example, blocking a background thread.

There is no easy solution, sorry.

As far as me personally ... if a library needs an async strategy I would lean towards making an async library. But it depends on what kind of library it is, whether there were any backward compatibility issues, etc. And the first thing I looked at was another type of extensibility.



as you can read here:

Async all the way

Asynchronous code reminds me of the story of a man who mentioned that the world was suspended in space and was immediately challenged by an elderly lady, claiming that the world was resting on the back of a giant turtle. When the man asked what a turtle was, the lady replied, "You are very smart, young man, but his turtles are all the way!" When you convert synchronous code to asynchronous code, you will find that it works best if the asynchronous code calls and is called by other asynchronous code - up to (or "up" if you like). Others also noticed the spread of asynchronous programming and called it "contagious" or compared it to a zombie virus. Whether turtles or zombies, it is definitely true that asynchronous code tends to render the surrounding code asynchronous.This behavior is common to all types of asynchronous programming, not just the new async / await keywords.

"Async all the way" means that you should not mix synchronous and asynchronous code without carefully considering the consequences. In particular, it is usually a bad idea to block asynchronous code by calling Task.Wait or Task.Result. This is a particularly common problem for programmers who dip their fingers into asynchronous programming by transforming only a small portion of their application and wrapping it in a synchronous API so the rest of the application is isolated from changes. Unfortunately, they run into deadlock issues. After answering many questions related to asynchronous messaging on the MSDN forums, stack overflow and email, I can say this is the most frequently asked question by asynchronous newbies after learning the basics: "Why is my partially sandboxed asynchronous code? "



All Articles