Creating asynchronous wrappers for long-running tasks is pointless in an ASP.NET context and does nothing but hurt performance in several ways.
Running synchronous methods asynchronously on a thread pool thread makes sense when offloading a GUI thread or another special thread. In that case, the method should be invoked asynchronously by the caller on that special thread in whichever way the caller sees fit (using e.g. Task.Run
, which should generally not be used in an implementation of an async method). In ASP.NET however, there's only thread pool threads, and none need to (and indeed should not) be offloaded in this manner for several reasons.
This is put most clearly by Stephen Cleary (who, after all, wrote the book on concurrency in C#) in the blog post Task.Run Etiquette Examples: Don't Use Task.Run in the Implementation
That’s why one of the principles of ASP.NET is to avoid using thread pool threads (except for the request thread that ASP.NET gives you, of course). More to the point, this means that ASP.NET applications should avoid Task.Run
.
[...]
In fact, the only place we really need an asynchronous calculation is when we call it from the UI thread.
The whole article is highly recommended and highlights various problems with offloading in ASP.NET.
Further reading: