I've searched a lot of information surrounding this topic and I understand the general premises of:
- Await is a handing off of control from the callee backer to the caller
- Most Modern I/O doesn't use real threading in underlying architecture
- Most async methods do not explicitly spin up their own threads (i.e. Web Requests)
The last bullet in particular is what I want to discuss. To future-proof this let's use an example as a medium for explanation. Let's assume this is the code block:
public async Task<int> LongOperationWithAnInt32ResultAsync(string input)
{
/// Section A
_ = int.TryParse(input, out var parsedInt)
parsedInt = SyncOperationWithAnInt32Result(parsedInt);
/// Section B
await MyCustomTaskThatIWantAwaited();
/// Section C
return parsedInt;
}
private Task MyCustomTaskThatIWantAwaited()
{
/// Section D
AnotherSyncOperationWithVoidResult();
/// Section E
return Task.CompletedTask;
}
The method LongOperationWithAnInt32ResultAsync(string) will perform synchronously even though this is not the intended effect.
This is because when the caller enters the callee at Section B, the code from Section D and Section E are executed immediately and are not awaited. This behavior is changed if, Section D is removed and, Section E was "return Task.Run(() => AnotherSyncOperationWithVoidResult())" instead. In this new Section E, the awaitable being tracked becomes the thread from Task.Run (wrapped with the returned Task).
If you replace Section B with "await Task.Delay(10000);" or "await FunctionalWebRequestAsync();" it works as intended. However, to my knowledge, neither of these internally generate a thread to be followed - so what exactly is being awaited?
I've accepted the main answer because it really helped me understand my misconception on Task functionality, but please also refer to my answer as well. It may be what you're looking for.