C#5.0 Asynchronous Programming Async and Await--Understanding the relationship between asynchronous methods and threads

This time, let's understand the relationship between asynchronous methods and threads

 

Create a new console program code as follows

static void Main(string[] args)
        {
            Console.WriteLine( " \nEnter the Main() method, execute the thread ID: {0}, from the thread pool? {1}, is the background thread? {2} " , Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread, Thread.CurrentThread.IsBackground);
            TestDoWorkAsync();
            Console.WriteLine( " \nReturn to the Main() method, waiting for the user to tap any key to exit, the execution thread ID: {0}, from the thread pool? {1}, is the background thread? {2} " , Thread.CurrentThread. ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread, Thread.CurrentThread.IsBackground);
            Console.ReadKey();
        }

        private async static void TestDoWorkAsync()
        {
            Console.WriteLine( " \nEnter the TestDoWorkAsync() method, the code execution thread ID before the await statement: {0}, from the thread pool? {1}, is the background thread? {2} " ,Thread.CurrentThread.ManagedThreadId,Thread .CurrentThread.IsThreadPoolThread,Thread.CurrentThread.IsBackground);
             // The code before await is executed by the caller thread, and the code after await and before the next await is executed by the same thread in the thread pool
             // but in the UI program , the UI thread calls the async method, then the statement after await is executed by the UI thread, not by the thread in the thread pool
             // TODO When we use await to wait for an asynchronous operation, by default, it will capture the current thread synchronous context, wait for the execution of the asynchronous method to end, the subsequent code will be packaged together, call the SyncContext.Post method, and push it to the previous synchronous thread context for execution
             // but the statement after await calls this method and passes the parameters as false await DoWork().ConfigureAwait(false); can notify the system not to capture the thread synchronization context, it will not be executed in the thread context captured before post to await, but directly use the thread that currently completes the asynchronous task to execute, avoiding the thread toggle 
            int result = awaitDoWork();
            Console.WriteLine( " \nExit TestDoWorkAsync() method, code execution thread ID after await statement: {0}, from thread pool? {1}, background thread? {2} " , Thread.CurrentThread.ManagedThreadId, Thread .CurrentThread.IsThreadPoolThread, Thread.CurrentThread.IsBackground);
            Console.WriteLine( "The result is {0} " ,result);
        }

        static Task<int> DoWork()
        {
            
            return Task.Run(() =>
            {
                Console.WriteLine( " \nUse TPL to run the DoWork method, the thread ID responsible for execution: {0}, from the thread pool?{1}, is the background thread?{2} " ,
                    Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread,
                    Thread.CurrentThread.IsBackground);
                Thread.Sleep(2000);
                return 5;
            });
        }

Take a look at the execution result

It can be seen that the caller thread will open a new thread to execute the await method when it executes await here, and returns immediately, so before the await DoWork(); method and after the TestDoWorkAsync(); method are executed by the main thread , and the statements after the asynchronous method DoWork() and DoWork are executed by the new thread

Take a look at the calling process

                              

 

 

 Summary: The code in the same method, with await as the boundary, is divided into two or more blocks (depending on the number of await statements), and then a thread in the thread pool is responsible for executing them

 

 

 

But there are some changes when it comes to the UI thread, which is also a bit difficult for me to understand

For example, call this method in the button response event

private async void UseAsync()
        {
            lblInfo.Text = " Wait for backgrounder to finish " ;
            btnLanch.Enabled = false;
            string result = await SayHelloToAsync("张三");
            
            lblInfo.Text = result;
            btnLanch.Enabled = true;
        }

        private Task<string> SayHelloToAsync(string name)
        {
            return Task.Factory.StartNew(() => SayHelloTo(name));
        }

Here, after the SayHelloToAsync() method is executed, the UI controls will be updated. The call of the Yinwei UseAsync method is triggered when the user clicks the button, which is an asynchronous call started in the UI thread, so after the execution, the following code will Pushed to the UI thread will execute

When we use await to wait for an asynchronous operation, by default, it will capture the synchronization context of the current thread, wait for the execution of the asynchronous method to end, and the subsequent code will be packaged together, 
call the SyncContext.Post method, and push it to the previous synchronization Execution in thread context
According to my practice, this situation only occurs in programs with UI interface. In console programs, after await is executed asynchronously, the following code will still be executed by a new thread, not by calling Thread execution.
But I feel that there is a hole here, first dig here, and then fill it. (I guess in a console program, the thread synchronization context of await is the new thread and not the caller thread)

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325090573&siteId=291194637