The async/await implementation will never fall back to thread pool by itself. Tasks are "futures", and in that sense a thread/task pool may be used in async/await when you need to run tasks in parallel. But when a thread pool is used is always under the control of the programmer.
Task is a more basic concept than threads. Tasks are about asynchronous execution, thread about parallel execution. Parallel execution is inherently asynchronous, but asynchronous execution is not parallel.
Indeed, that it the whole idea behind async/await: Enable the asynchronous model without the overhead of multiple threads.
It does use a threadpool scheduler by default for a console app. Yes, I could override that if I wanted to.
For UI threads (WPF, WinForms) it is essential that the code continues on the original thread. This the synch context used in WPF/WinForms will post the continuation on the original thread once it becomes available (thrugh the big message loop).
For ASP.NET threads, requests are processed from a thread pool. The ASP.NET synch context IIRC will schedule continuation on any ASP.NET managed thread.
So yes, you may see your code (esp. in console apps) executing on another thread after an async call, but that does not mean that .NET schedules your tasks on a thread pool. There is still only a single thread of execution at any one time, until you explicitly use a thread pool (e.g. Task.Run)
for (var i = 0; i < 1000000; i++) {
var unused_task_var = RunTaskAsync();
}
await RunMainMonitoringTaskAsync();
And I purposefully wasn't calling await on "unused_task_var". And this was doing what I wanted, running all those tasks on multiple background threads in the pool, as long as RunTaskAsync method itself yielded once early on in its function (to return control back to the for loop).tl;dr If you call an async method and don't await on it, it will be parallelized - for a console app, at least.
Honestly, I don't find the MS docs on this to be that great. Not 100% sure I'm even doing it the right way here. Everybody says use Task.Run but that is for CPU bound tasks. I want to run a ton of IO waiting tasks.
edit: looks like I'm doing it right. See "Async Composition" @ https://blog.stephencleary.com/2012/02/async-and-await.html
In general it works pretty well until you need more than the defaults offer, then it becomes almost an exercise in frustration.