0

If I am making a library for my team that will be shared between multiple projects and the library is doing work that lends itself to be a good candidate for async/await, should I also include non-async/await versions of the code? It seems like a lot of duplicate code, but I don't see any alternative. Is this just the price you pay for having the ability to have increased thread pool utilization?

Just to be clear, I am not asking if I should include a synchronous wrapper method, which is all I have been able to find answers to.

For example, I might have a long running SQL query. I would then need to implement this interface with two methods that are almost identical, one using the async methods on SqlConnection and SqlCommand, and one not using them. Is this the correct approach or am I missing something?

public interface ILongRunningOperation
{
    Response LongRunningOperation();

    Task<Response> LongRunningOperationAsync();
}

Thanks!

Christopher Haws
  • 1,715
  • 21
  • 21
  • Nope. Do not forget that you can also use the synchronous form of LongRunningOperation().Wait(); to achieve the same results. It is an obscure extension, and often overlooked. – JamieMeyer Dec 03 '16 at 03:21
  • The blog post [Should I expose synchronous wrappers for asynchronous methods?](https://blogs.msdn.microsoft.com/pfxteam/2012/04/13/should-i-expose-synchronous-wrappers-for-asynchronous-methods/) concludes "Please try hard not to; leave it up to the consumer of the your method to do so if they must. You should consider the possibility that someone will consume your functionality synchronously, so code accordingly, with as few dependences on the threading environment as possible." – Lance U. Matthews Dec 03 '16 at 03:38
  • Related: [async vs non-async methods in a new library](http://stackoverflow.com/q/25968037/150605) – Lance U. Matthews Dec 03 '16 at 03:41
  • 2
    @JamieMeyer you may want to re-read http://stackoverflow.com/questions/13140523/await-vs-task-wait-deadlock before making advice to use `.Wait()`. – Alexei Levenkov Dec 03 '16 at 03:46
  • @AlexeiLevenkov Yes, I am aware of that, and agree with the accepted answer in the your reference. That is precisely my interpretation of the OP ask above. In all cases, the decision is left an an exercise for the reader. After all, it is an opinion-based question. Thanks ;-) – JamieMeyer Dec 03 '16 at 03:58
  • I have already read the article and Q/A's posted and have a decent understanding of the implications of wrapping the `async` method with a `sync` method which is why I want to avoid doing so. Depending on where you are running the code, this can cause deadlocks, unnecessary context switching, and larger IL output. You can call `.ConfigureAwait(false)` if you don't need items off the context, but this has its own set of complexities and downfalls. Is the correct answer then to really duplicate the code, having one method call the non-async methods, and the other method call the async methods? – Christopher Haws Dec 03 '16 at 04:21

1 Answers1

0

I would say the answer is "no" in the general case. Naturally-asynchronous operations (e.g., those with I/O) are best represented via asynchronous APIs.

However, there are some scenarios where you would want a similar synchronous API. Backwards compatibility is one common reason. Another is if you just want to provide simpler synchronous consumption.

If you do decide to provide synchronous APIs, I recommend you take a look at the "boolean argument hack" in my MSDN article on brownfield async. You still end up with a synchronous and asynchronous implementation, but it's in one method so your logic isn't duplicated.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810