Task and async / await Detailed

First, what is asynchronous

  Synchronous and asynchronous method is mainly used for modification. When a method is called, the caller needs to wait for the process is finished and return to continue, we call this method is synchronous method; when a method is called to return immediately and obtain a thread executing inside the method of service, call those who do not wait for the process is finished, we call this method is asynchronous.

  That the benefits of asynchronous non-blocking (the calling thread will not be suspended to wait for child threads to complete), so we do not need to immediately use some of the results, the more time-consuming task to execute asynchronously, can improve the operating efficiency of the program. net4.0 launched on the basis of the Task class ThreadPool, Microsoft strongly recommended to perform asynchronous tasks using Task, now asynchronous method C # class library basically used the Task; net5.0 launched async / await, make asynchronous programming more For the convenience. This part describes the Task, async / await relevant content, the way other asynchronous operation will introduce the next one.

Two, Task Introduction

  Task is launched on the basis of the ThreadPool, we simply understand the next ThreadPool. There are several ThreadPool number of threads, if there are tasks to deal with, will get a free from the thread pool thread to perform the task, the task execution thread does not finish after the destruction, but the thread pool is recycled for subsequent tasks. When all thread pool threads are busy, when there are new tasks to be processed, the thread pool will create a new thread to handle the task, if the maximum number of threads setting, the task will be queued for other tasks release thread after the execution. Thread pools can reduce thread creation, save money, see a chestnut ThreadPool it

Copy the code
        the Main void static (String [] args) 
        { 
            for (int I =. 1; I <= 10; I ++) 
            { 
                // the ThreadPool tasks 
                the ThreadPool.QueueUserWorkItem (the WaitCallback new new ((obj) => { 
                    Console.WriteLine ($ "section {obj} task execution "); 
                }), I); 
            } 
            the Console.ReadKey (); 
        }
Copy the code

  Code execution via ThreadPool top ten tasks, the results are:

   ThreadPool can be reduced relative to the Thread for thread creation, effectively reduce system overhead; but can not control the execution order ThreadPool thread, we can not obtain the thread pool thread cancellation notice / anomaly / done that we can not effectively monitor and control thread thread pool.

1 Task to create and run

  We know the shortcomings of the ThreadPool: We can not control the order of execution threads in the thread pool, thread pool threads can not get canceled / error / completion notification . net4.0 launched a Task, Task advantages of owning thread pool on the basis of the ThreadPool, but also solve the drawbacks of using a thread pool is not easy to control.

First look at how to create and run a Task, Task creation and manner of implementation of the following three:

Copy the code
        the Main void static (String [] args) 
        { 
            //1.new instantiate a Task, Start method is started through 
            the Task Task the Task new new = (() => 
            { 
                the Thread.Sleep (100); 
                Console.WriteLine ($ " hello, task1 thread ID is Thread.CurrentThread.ManagedThreadId} { "); 
            }); 
            task.Start (); 

            //2.Task.Factory.StartNew(Action Action) to create and start a the Task 
            the Task Task2 = Task.Factory .StartNew (() => 
              { 
                  the Thread.Sleep (100); 
                  Console.WriteLine ($ "Hello, Task2 thread ID is Thread.CurrentThread.ManagedThreadId} {"); 
              });

            //3.Task.Run(Action action) task queue in the thread pool, and returns a start the Task 
            the Task Task.Run Task3 = (() => 
              { 
                  the Thread.Sleep (100); 
                  Console.WriteLine ($ "Hello , task3 thread ID is Thread.CurrentThread.ManagedThreadId} { "); 
              }); 
            Console.WriteLine (" execution of the main thread ");! 
            the Console.ReadKey (); 
        }
Copy the code

Execution results are as follows:

  We see the first print "execution of the main thread", and then print each task, explain the Task will not block the main thread. Task top of chestnuts did not return value, we can also create a return to the values ​​of Task <TResult>, and use basically the same no return value, we simply modify chestnuts on top of the code is as follows:

Copy the code
        the Main void static (String [] args) 
        { 
            ////1.new instantiate a Task, Start method is started through 
            the Task <String> the Task Task new new = <String> (() => 
            { 
                return $ "Hello, task1 ID for the Thread.CurrentThread.ManagedThreadId} { "; 
            }); 
            task.Start (); 

            ////2.Task.Factory.StartNew(Func FUNC) to create and start a the Task 
           the Task <String> = Task2 the Task. Factory.StartNew <String> (() => 
            { 
                return $ "Hello, Task2 ID for the Thread.CurrentThread.ManagedThreadId} {"; 
            }); 

            ////3.Task.Run(Func FUNC) task in thread pool queue, go back and start a Task  
           the Task <String> Task.Run Task3 = <string>(() =>
            {
                return $"hello, task3的ID为{ Thread.CurrentThread.ManagedThreadId}";
            });

            Console.WriteLine("执行主线程!");
            Console.WriteLine(task.Result);
            Console.WriteLine(task2.Result);
            Console.WriteLine(task3.Result);
            Console.ReadKey();
        }
Copy the code

  Note task.Resut getting results will be blocking the thread that is not performed if the task is complete, the task will wait to perform the acquisition is completed Result, and then execute the code behind the program runs as follows:   

  Perform all of the top chestnut Task is asynchronous and does not block the main thread. In some scenes we want Task executed synchronously how to do it? Task provides   task.RunSynchronously () is used to synchronize execution Task task, as follows:

Copy the code
        the Main void static (String [] args) 
        { 
            Task Task Task new new = (() => 
            { 
                the Thread.Sleep (100); 
                Console.WriteLine ( "End Task execution!"); 
            }); 
            // synchronous execution, task will block the main thread 
            task.RunSynchronously (); 
            Console.WriteLine ( "main thread execution end!"); 
            Console.ReadKey (); 
        }
Copy the code

Execution results are as follows:

 2 Task blocking method (Wait / WaitAll / WaitAny)

1 Thread blocked thread method

  When using Thread, we know with thread.Join () method to block the main thread. Look at an example:

Copy the code
        the Main void static (String [] args) 
        { 
            the Thread ThI the Thread new new = (() => { 
                the Thread.Sleep (500); 
                Console.WriteLine ( "Thread 1 is finished!"); 
            }); 
            th1.Start (); 
            the thread new new Th2 = the thread (() => { 
                the Thread.Sleep (1000); 
                Console.WriteLine ( "thread 2 is finished!"); 
            }); 
            th2.Start (); 
            // block the main thread 
            th1.Join () ; 
            th2.Join (); 
            Console.WriteLine ( "main thread is finished!"); 
            the Console.ReadKey (); 
        }
Copy the code

  If two Join comment out, the results are: first, the main thread is finished [print], and the results after the addition of the following two methods Join realized thread blocks:

2 Task的Wait/WaitAny/WaitAll方法

   Thread Join method to block the calling thread, there are some drawbacks: ① if we are to achieve the blocking of many threads, each thread should call a Join method; ② If we want all of the threads is finished (or any thread when finished), immediately unblocked, use the Join method is not easy to achieve. Task provides   Wait / WaitAny / WaitAll method, it can more easily control thread blocks.

  task.Wait () represents the waiting task is finished, the function is similar to thead.Join ();   Task.WaitAll (Task [] Tasks) means that only perform all the task done and then unblock;   Task.WaitAny (Task [] Tasks ) that as long as there is a task is finished to unblock, see a chestnut: 

Copy the code
        the Main void static (String [] args) 
        { 
            the Task Task1 the Task new new = (() => { 
                the Thread.Sleep (500); 
                Console.WriteLine ( "Thread 1 is finished!"); 
            }); 
            task1.Start (); 
            the Task new new Task2 = the Task (() => { 
                the Thread.Sleep (1000); 
                Console.WriteLine ( "thread 2 is finished!"); 
            }); 
            task2.Start (); 
            // block the main thread. task1, task2 were completed and then executes the main thread 
       // Perform [task1.Wait (); task2.Wait ();} can achieve the same functionality 
            Task.WaitAll (new new the Task [] {task1, task2}); 
            Console.WriteLine ( "The main thread is finished!"); 
            Console.ReadKey (); 
        }
Copy the code

  Execution results are as follows:

  If the chestnuts in WaitAll replaced WaitAny, then the task is finished it will either lift the thread is blocked, the results are: First print] [Thread 1 is finished, then [print] The main thread is finished, the final print execution [Thread 2 completed]

 3 Task continuation operation (WhenAny / WhenAll / ContinueWith)

  On top of Wait / WaitAny / WaitAll method returns a value of void, these methods simply realize blocked thread. We now want all the task is finished (or any task is finished), the follow-up operation started, how to achieve it? Then you can use WhenAny / WhenAll method, and these methods returns a task execution completion instance.  task.WhenAll (Task [] tasks) are represented by all of the task is finished and then to perform a subsequent operation,  task.WhenAny (the Task [] Tasks) represents a task performed after the completion of any subsequent operations begin. See a chestnut:

Copy the code
        the Main void static (String [] args) 
        { 
            the Task Task1 the Task new new = (() => { 
                the Thread.Sleep (500); 
                Console.WriteLine ( "Thread 1 is finished!"); 
            }); 
            task1.Start (); 
            the Task new new Task2 = the Task (() => { 
                the Thread.Sleep (1000); 
                Console.WriteLine ( "thread 2 is finished!"); 
            }); 
            task2.Start (); 
            // Task1, Task2 finished after performing subsequent execution operation 
            Task.WhenAll (Task1, Task2) .ContinueWith ((T) => { 
                the Thread.Sleep (100); 
                Console.WriteLine ( "follow up is completed!"); 
            }); 

            the Console.ReadKey ();
        }
Copy the code

  Results of the following, we see WhenAll / WhenAny method does not block the main thread, when all of the task are WhenAll method to finish before a subsequent operation; if the replace chestnut WhenAll into WhenAny, as long as there is a thread of execution complete follow-up operation will begin, no demonstration here.

   Upper chestnuts can also  Task.Factory.ContinueWhenAll (Task [] tasks, Action continuationAction) and  to achieve Task.Factory.ContinueWhenAny (Task [] tasks, Action continuationAction), modify the code below the upper chestnuts, the results of the same.

Copy the code
       the Main void static (String [] args) 
        { 
            the Task Task1 the Task new new = (() => { 
                the Thread.Sleep (500); 
                Console.WriteLine ( "Thread 1 is finished!"); 
            }); 
            task1.Start (); 
            the Task new new Task2 = the Task (() => { 
                the Thread.Sleep (1000); 
                Console.WriteLine ( "thread 2 is finished!"); 
            }); 
            task2.Start (); 
            // achieved by TaskFactroy 
            Task.Factory.ContinueWhenAll (new new the Task [] {Task1, Task2}, (T) => 
            { 
                the Thread.Sleep (100); 
                Console.WriteLine ( "follow up"); 
            });

            Console.WriteLine ( "main thread is finished!"); 
            Console.ReadKey (); 
        }
Copy the code

 4 Task canceled task (CancellationTokenSource)

1 Thread cancel task execution

  Task before our mission uses a Thread, Thread how to cancel task? The general process is: to set a variable to control whether to stop the task, such as setting a variable isStop, then thread polls to view isStop, if isStop is true stopped, as follows:

Copy the code
        the Main void static (String [] args) 
        { 
            BOOL = ISSTOP to false; 
            int index = 0; 
            // open a thread tasks 
            the Thread ThI the Thread new new = (() => 
              { 
                  the while (ISSTOP)! 
                  { 
                      the Thread.Sleep (1000) ; 
                      Console.WriteLine ($ "on {++ index} execution, the thread running ..."); 
                  } 
              }); 
            th1.Start (); 
            cancel task execution // after five seconds 
            Thread.Sleep (5000); 
            = to true ISSTOP; 
            the Console.ReadKey (); 
        }
Copy the code

2 Task to cancel the task execution

  Task has a special class  CancellationTokenSource to cancel task execution, or the use of top of the examples, we modify the code below, the effect of running unchanged.

Copy the code
        the Main void static (String [] args) 
        { 
            CancellationTokenSource new new CancellationTokenSource = Source (); 
            int index = 0; 
            // Open a task execution task 
            the Task Task1 the Task new new = (() => 
              { 
                  the while (source.IsCancellationRequested)! 
                  { 
                      the Thread .sleep (1000); 
                      Console.WriteLine ($ "on {++ index} execution, the thread running ..."); 
                  } 
              }); 
            task1.Start (); 
            cancel task execution // after five seconds 
            thread. SLEEP (5000);  
            //source.Cancel () method request to cancel the task, IsCancellationRequested will become true
            source.Cancel (); 
            the Console.ReadKey ();
        }
Copy the code

   CancellationTokenSource do more than just cancel task execution, we can use   source.CancelAfter (5000) tasks automatically canceled after 5 seconds, you can also   sign up cancel callback function tasks triggered source.Token.Register (Action action), that is, the task is registered canceling action will be executed. See a chestnut:

Copy the code
        Main void static (String [] args) 
        { 
            CancellationTokenSource Source = new new CancellationTokenSource (); 
            // cancel the event registration tasks 
            source.Token.Register (() => 
            { 
                Console.WriteLine ( "xx perform operations after the task was canceled!" ); 
            }); 

            int index = 0; 
            // open a task execution task 
            the task Task1 the task new new = (() => 
              { 
                  the while (source.IsCancellationRequested)! 
                  { 
                      the Thread.Sleep (1000); 
                      Console.WriteLine ($ "section {++ index} execution, the thread running ... "); 
                  }  
              });
            task1.Start (); 
            // cancel delay, the same effect as the Thread.Sleep (5000); source.Cancel (); 
            source.CancelAfter (5000); 
            the Console.ReadKey (); 
        }
Copy the code

  Execution results are as follows, 5th cancel the callback is executed after printing, it is because, when the implementation of the 5th cancel the task has been passed while () judgment, the task has been performed in:

   Finally spotted a cross-thread chestnuts, click on the button to start a task, assignment to tetxtbox, we changed the Thread Task, the following code:

Copy the code
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void mySetValueBtn_Click(object sender, EventArgs e)
        {
            Task.Run(() =>
            {
                Action<int> setValue = (i) => { myTxtbox.Text = i.ToString(); };
                for (int i = 0; i < 1000000; i++)
                {
                    myTxtbox.Invoke(setValue,i);
                }
            });
        }
    }
Copy the code

  Run the following interface, task assignment does not block the UI thread:

Third, the method of the asynchronous (async / await)

1. Simple understanding

  Appear in C # 5.0 in  async and await, make asynchronous programming easier. We get a look at the contents of the file chestnuts:

Copy the code
    Program class 
    { 
        static void the Main (String [] args) 
        { 
            String Content = GetContentAsync (Environment.CurrentDirectory @ + "/ test.txt") the Result;. 
            // calls the synchronization method 
            // string content = GetContent (Environment.CurrentDirectory + @ "/test.txt"); 
            Console.WriteLine (content); 
            the Console.ReadKey (); 
        } 
        // read the contents of the file asynchronously 
        the async static the Task <String> GetContentAsync (String filename) 
        { 
            
            the FileStream the FileStream new new FS = (filename, FileMode .Open); 
            var bytes = new new byte [fs.Length]; 
            // asynchronous read method ReadAync content, without blocking the thread
            Console.WriteLine ( "Start read file");
            the await fs.ReadAsync len = int (bytes, 0, bytes.Length); 
            String Result = Encoding.UTF8.GetString (bytes); 
            return Result; 
        } 
        // read the contents of the file synchronization 
        static GetContent String (String filename) 
        { 
            the FileStream FS the FileStream new new = (filename, FileMode.Open); 
            var bytes = new new byte [fs.Length]; 
            // read the contents of the read method of synchronization, blocked thread 
            int len = fs.Read (bytes, 0, bytes.Length); 
            String = Encoding.UTF8.GetString Result (bytes); 
            return Result; 
        } 
    }
Copy the code

  test.txt content is [hello world! ] Implementation of the results:

  On top of chestnuts also wrote the synchronization of read, the main function of synchronizing annotations can be removed to read the file contents. We can see the asynchronous and synchronous read the code read basically the same. async / await asynchronous make coding easier, as we can write the same synchronization code to write asynchronous code. Note that a small problem: the asynchronous method signature method returns a value Task <T>, the return code is T. GetContentAsync chestnuts in the upper signature return value Task <string>, and returns a value of the code string. Keep in mind that the details of our analysis of asynchronous code helpful.

  Asynchronous method signature of the return value of the following three:

    ① Task <T>: If you want to call a method to obtain a T type by calling the asynchronous method's return value, then the signature must be a Task <TResult>;

    ② Task: If you do not want to call a method to obtain a value through asynchronous method, simply want to track the status of an asynchronous method execution, then we can set the return value of asynchronous method signature Task;

    ③ void: If you call the method just about asynchronous method invocation, and no other way to do asynchronous interaction, we can set the return value of asynchronous method signature void, this form also known as "call and forget."

  Summary : Here is simple to use Task, async / await has basically ended, some of the advanced features work until the study met again. Introduced by the upper side, we know async / await Task is based, and is packaged Task ThreadPool improvement, mainly in order to more effectively control the thread pool threads (the thread of the ThreadPool, it is difficult to control which is performed by the code order, the task continuation and cancellation, etc.); ThreadPool is to reduce the number and cost management to create Thread Thread based, the main purpose of Thread. async / await Task is C # is more advanced, but also Microsoft's heavily promoted features, we can try to use the Task in development instead Thread / ThreadPool, processing local IO and network IO task is to try to use async / await to improve task efficiency .

Guess you like

Origin www.cnblogs.com/soundcode/p/11465125.html