I have a fragile grasp of how the await keyword works, and I want to extend my understanding of it a bit.
The issue that still makes my head spin is the
In your first and second example the TestAsync is still waiting for the call to itself to return. The difference is the recursion is printing and returning the thread to other work in the second method. Therefore the recursion isn't fast enough to be a stack overflow. However, the first task is still waiting and eventually count will reach it's max integer size or stack overflow will be thrown again. The point is the calling thread is returned to but the actual async method is scheduled on the same thread. Basically, the TestAsync method is forgotten until await is complete but it is still held in memory. The thread is allowed to do other things until await completes and then that thread is remembered and finishes where await left off. Additional await calls store the thread and forget it again until await is again complete. Until all awaits are completed and the method therefore completes the TaskAsync is still in memory. So, here's the thing. If I tell a method to do something and then call await for a task. The rest of my codes elsewhere continues running. When await is complete the code picks back up there and finishes and then goes back to what it was doing at that time right before it. In your examples your TaskAsync is always in a tombstoned state (so to speak) until the last call complete and returns the calls back up the chain.
EDIT: I kept saying store the thread or that thread and I meant routine. They are all on the same thread which is the main thread in your example. Sorry if I confused you.