How to safely mix sync and async code?

Igor Gatis picture Igor Gatis · Jun 19, 2014 · Viewed 12.1k times · Source

I have this library which is purely sync. It exposes sync methods and I have clients using it.

I changed the underlying implementation to async and exposed async methods for whoever wants to use it. But now I have lots of replicated code. Async code seems to perform better. I'd like existing clients to take advantage of it and I want to eliminate code repetition.

Is there any safe way to keep a sync signature and call async implementation?

I'm specifically afraid of deadlocks when calling .Result and .Wait.

Answer

Yuval Itzchakov picture Yuval Itzchakov · Jun 19, 2014

I strongly encourge you not to do this

First, read Should I expose synchronous wrappers for asynchronous methods? and Should I expose asynchronous wrappers for synchronous methods? by Stephan Toub.

The main reasons I wouldn't do this:

  1. Sync over Async - As you said, deadlocks. Higher or lower down the call chain, using Result or Wait on async maybe risky business. It really depends on which platform you run (ASP.NET, UI, Console) as each one behaves a bit differently (Even when using ConfigureAwait(false))

  2. Async over Sync - Scalability. Once I see an async endpoint, I assume it is pure async, which for me, as the consumer of the API means there isn't any Thread spinning "behind my back". If your users assume the same, finding out that for every call to an async method a Thread Pool thread is used can drastically hurt performance when trying to scale out. If the users want to wrap a sync method with a Task.Run, leave it up to them to make that call and make their on judgement on how this will affect their application