Let's do a summary of the options that we have:
- Sync function wrapped with a coroutine: The biggest advantage is how explicit it is, but in doing so it's quite verbose.
- An async function with a specific dispatcher: While being less verbose, it's not as flexible because the caller can't decide which dispatcher should be used – which could be good if you really want to force the coroutine to a specific thread. Being explicit about it the function being asynchronous depends on the developer, which is less than ideal.
- An async function with a flexible dispatcher: Allows the caller to decide where to run the coroutine, but still depends on the developer giving a proper name to the function.
The best decision ...