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
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 (); }
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:
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 (); }
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:
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(); }
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:
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 (); }
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:
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 (); }
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:
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 (); }
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:
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 (); }
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.
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 (); }
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:
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 (); }
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.
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 (); }
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:
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 (); }
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:
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); } }); } }
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:
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; } }
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 .