Why is the initial thread not used on the code after the awaited method?

半腔热情 提交于 2021-02-10 18:15:10

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!