Description

The threadpool is an app-global resource, so you should leave the callers of your library to decide how and when they want to use it. Your library methods should not use the threadpool (Task.Run, Parallel.For, ...) internally in secret. Most of the time, they should have async signatures if and only if their internal implementations are truly async.

Sometimes you're forced to write a synchronous blocking method to fit into an older synchronous framework, but you still want to call new async APIs. There's no good answer here. People use Task.Wait() or Task.Result, which are bad solutions. Stephen Toub lists some less bad solutions here.

Sometimes you're trying to work in a modern asynchronous framework but you have to call legacy synchronous APIs. People use Task.Run here, but you should understand that there's simply no way to gain the scalability of async. For that you really need async all the way down. Once again, Stephen Toub fleshes out what to do here.

The Discussion

I have experienced many frustrations trying to learn how to cope when sync and async worlds collide. Thanks to your educational blog-videos about async patterns and pitfalls I am starting to get a handle on the issues.

I currently have a slight twist on meshing the synchronous and asynchronous worlds, hopefully you can provide some insight. There is an interface to a repository (IRepository ) that mostly defines CRUD operations to persist POCO models. Two actual IRepository implementations save data to a local database and the Azure table storage (either of which may take a while to handle operations), so it seems sensible for the IRepository interface definition to include async methods that return Tasks, for example:

But now a situation has arisen where I need an implementation of an IRepository using in-memory data structures like a dictionary. The API for adding and reading stuff from a Dictionary consists of synchronous methods, but the IRepository interfacedefinition has async bias. So, am I being stupid by wrapping the synchronous dictionary methods using returnTask.FromResult<T>() to fulfill the IRepositorysignature requirements? For example:

If this is a not a good idea, can you provide guidance on what to do when an interface contract you need to fulfill is async, but the specific implementation is based on synchronous methods? (of course the converse issue could also arise...)

@squizfloats - You've got the right idea. This is a situation where the overall API design is forcing you to have an async signature, even though your method itself isn't async in its implementation.

Please watch the next video in the series. That discusses EXACTLY this case. Actually it discusses it in the guise of "MemoryStream". Obviously Stream has to have async APIs since most streams (disk, network, ...) are asynchronous in nature. But when you come to implement MemoryStream, it has no natural async implementation. And so it uses Task.FromResult exactly as you described.

The video talks about several useful micro-optimizations specifically for this case. Worth considering.