问题
I do not understand how is the control returned to the caller when using async- await, since when i execute this code, the first thread gets practically destroyed when calling task inside the awaited method, and the thread that gives the result executes all remaining code.Below i have also drawn a diagram of how i thought the execution is, but it seems it is wrong.
Assumed workflow according to "returning control to the caller":
Results
Main
public static string GetThreadId => Thread.CurrentThread.ManagedThreadId.ToString();
static async Task Main(string[] args) {
Console.WriteLine("From main before async call , Thread:" + GetThreadId);
string myresult = await TestAsyncSimple();
Console.WriteLine("From main after async call ,Thread:" + GetThreadId);
Console.WriteLine("ResultComputed:" + myresult+",Thread:"+GetThreadId);
Console.ReadKey();
}
Async Task
public static async Task<string> TestAsyncSimple() {
Console.WriteLine("From TestAsyncSimple before delay,Thread:" + GetThreadId);
string result=await Task.Factory.StartNew(() => {
Task.Delay(5000);
Console.WriteLine("From TestAsyncSimple inside Task,Thread:" + GetThreadId);
return "tadaa";
});
Console.WriteLine("From TestAsyncSimple after delay,Thread:" + GetThreadId);
return result;
}
Can anyone point me to the right direction?Also what causes the new thread to get spawned?Always when starting a Task ?Are there other "triggers" besides tasks that create new threads which will execute the remaining code?
回答1:
async Main method is converted to something like this:
static void Main() {
RealMain().GetAwaiter().GetResult();
}
static async Task RealMain() {
// code from async Main
}
With that in mind, at "From main before async call" point you are on main application thread (id 1). This is regular (non thread pool) thread. You will be on this thread until
await Task.Factory.StartNew(...)
At this point, StartNew
starts a new task which will run on a thread pool thread, which is created or grabbed from pool if already available. This is thread 3 in your example.
When you reach await
- control is returned back to the caller, where caller in this case is thread 1. What this thread does after await is reched? It's blocked here:
RealMain().GetAwaiter().GetResult();
waiting for result of RealMain
.
Now thread 3 has finished execution but TestAsyncSimple()
has more code to run. If there were no synchronization context before await (the case here - in console application) - the part after await will be executed on available thread pool thread. Since thread 3 has finished execution of its task - it is available and is capable to continue execution of the rest of TestAsyncSimple()
and Main()
functions, which it does. Thread 1 all this time is blocked as said above - so it cannot process any continuations (it's busy). In addition it's also not a thread pool thread (but that is not relevent here).
After you reached Console.ReadKey
and pressed a key - Main
task finally completes, thread 1 (waiting for this task to complete) is unblocked, then it returns from real Main function and process is terminated (only at this point thread 1 is "destroyed").
来源:https://stackoverflow.com/questions/48785663/why-is-the-initial-thread-not-used-on-the-code-after-the-awaited-method