What is a Task?
Task is a class used to implement multithreading. In the previous version, Thread and ThreadPool already exist. Why should we propose the task class? This is because it is very troublesome to directly operate Thread and ThreadPool, pass parameters to the Thread, obtain the return value of the Thread and start and stop the Thread. Therefore, Microsoft engineers repackage the Thread. This is task. It can be said that task is based on Thread, Therefore, when multithreading, task is our first choice.
The thread of the task is the background thread.
Essentially, a task is an enhanced API for a thread pool.
Disadvantages of thread pool
1. It is inconvenient to get results from thread pool
2. Asynchronous processing is inconvenient
3. Continuous asynchronous operation is inconvenient
Purpose:
Scenario 1: three concurrent requests obtain data through three interfaces. We hope to obtain the data of all interfaces for the next business processing.
Scenario 2: three concurrent requests. As long as one of them is completed, an event result will be triggered.
Statement of Task
There are two ways to declare a Task:
a. Declare through new
Task obj = new Task();
b. Through task Factory. Startnew
Task.Factory.StartNew(MyMethod);
The difference between the two declaration methods: the first declaration method must use obj to start the thread Start() and through task Factory. The startnew method is not used.
Task creation
1. Constructor creation
static void Main(string[] args) { Task task = new Task(() => { // True thread pool thread Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread); }); task.Start(); Console.ReadLine(); }
2.Task.Factory.StartNew create
Note: in the task factory mode, the task will be called and executed immediately.
static void Main(string[] args) { Task.Factory.StartNew(() => { // True thread pool thread Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread); }); Console.ReadLine(); }
3. Do not use thread pool settings to create
static void Main(string[] args) { Task task = new Task(() => { // False do not use thread pool Console.WriteLine(Thread.CurrentThread.IsThreadPoolThread); }, TaskCreationOptions.LongRunning); task.Start(); Console.ReadLine(); }
Get task return value
Task<string> task = new Task<string>(() => { DoSomething(); return "Here is the result of execution completion"; }); task.Start(); Console.WriteLine(task.Result);
Callback of task
task.ContinueWith
(1) Support one task connected to multiple ContinueWith;
(2) ContinueWith returns the next generation task, and the next generation can continue ContinueWith;
Task<string> task = new Task<string>(() => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); return "boy,"; }); task.ContinueWith((t) => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); Console.WriteLine(t.Result + "come on."); }); task.Start(); Console.ReadLine();
Thread waiting and continuation of Task
Thread waiting and continuation under Task mainly include the following categories:
Wait
For a single Task instance, you can make a thread enter the wait.
WaitAny
The main thread will execute as long as one thread ends, otherwise it will get stuck.
WatiAll
Indicates that the main thread resumes after all the tasks in the task list have ended.
WhenAny
It means that after any task in the task list is completed, it will be triggered with ContinueWith.
WhenAll
It means that after all tasks in the task list are completed, the callback trigger is carried out in cooperation with ContinueWith.
Note: both WhenAny and WhenAll start a new thread for execution and do not jam the main thread.
TaskFactory
TaskFactory can start threads, and of course, it also corresponds to the waiting and continuation of threads.
ContinueWhenAny: equivalent to Task's WhenAny+ContinueWith
ContinueWhenAll: equivalent to Task's WhenAll+ContinueWith
Example code:
//1.ContinueWhenAny Task.Factory.ContinueWhenAny(taskList.ToArray(),m=>{ Console.WriteLine("") }) //2.ContinueWhenAll Task.Factory.ContinueWhenAll(taskList.ToArray(),m=>{ Console.WriteLine("") })
Complete code demonstration, create console:
using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace ConsoleApp1 { class Program { public static void Main(string[] args) { List<Task<string>> taskList = new List<Task<string>>(); Task<string> t1 = new Task<string>(() => { return GetName(); }); Task<string> t2 = new Task<string>(() => { return GetMongo(); }); taskList.Add(t1); taskList.Add(t2); t1.Start(); t2.Start(); Task.WhenAll(taskList.ToArray()).ContinueWith(x => { Console.WriteLine("The task is completed"); Console.WriteLine(x.Result[0]); Console.WriteLine(x.Result[1]); }); Console.ReadLine(); } public static string GetName() { Thread.Sleep(5000); return "MSSQL"; } public static string GetMongo() { Thread.Sleep(10000); return "MongoDB"; } } }
The result is that the code runs for 10 seconds and outputs the corresponding contents in turn.
await and async keywords
When it comes to the return value of Task, we have to say await and async keywords. When the function is marked with async, the return value must be void, Task, Task < T >. When the return value is Task < T >, only T type needs to be returned inside the function, and the compiler will automatically wrap it into Task < T > type. The await keyword must be used within functions with async tags.
for instance:
static void Main(string[] args) { Console.WriteLine("Call main thread"); Task<string> s = Testasync(); Console.WriteLine(s.Result); Console.ReadKey(); } static async Task<string> Testasync() { Console.WriteLine("function Task before" + Thread.CurrentThread.ManagedThreadId); Task<string> t= Task.Run<string>(() => { Console.WriteLine("function Task" + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(); return "Thread test is me"; }); Console.WriteLine("function Task after" + Thread.CurrentThread.ManagedThreadId); var result = await t; return result; }
async/await is a key word introduced by C#5.0. Its purpose is to make asynchronous programming more concise and to comply with the general trend of asynchronous programming.
function
1. async/await can be used to simply create asynchronous methods, which can prevent time-consuming operations from blocking the current thread.
2. async/await is used to build asynchronous methods, which is more concise.
grammar
① Method uses async as a modifier
② Method contains one or more await expressions that represent tasks that can be completed asynchronously
③ There must be the following three return types: void, Task and Task < T >, of which the return objects of the latter two identify the work to be completed in the future, and the calling method and asynchronous method can continue to be executed.
④ The parameters of an asynchronous method can be of any type, but they cannot be out and ref parameters
⑤ By convention, Async is generally used as the suffix of asynchronous methods.
⑥ In addition to methods, Lambda expressions and anonymous functions can also be used as asynchronous objects.
If await does not appear in async, the method becomes a synchronization method.
Control flow of asynchronous method
1 first, the part before the first await, which should be a small amount of code without waiting for a long time.
2await expression, which indicates the tasks that need to be executed asynchronously. There can be multiple awaits.
3 the rest of the code for the method that appears after the await expression.
give an example:
Example 1:
public static async Task DoSomethingAsync() { Console.WriteLine("Asynchronous method synchronization part 1"); long sum = 0; sum = await Task.Run(() => { Console.WriteLine("Asynchronous execution part 1,thread ID: {0}",Thread.CurrentThread.ManagedThreadId); Thread.Sleep(2000); long result = 0; for (var i = 0; i < 1000000000; i++) { result += i; } Console.WriteLine("End of asynchronous execution section"); return result; }); Console.WriteLine("Calculation results{0}", sum); }
Example 2:
public static async void DoSomethingAsync() { Task t1 = new Task(()=> { Console.WriteLine("Asynchrony started,Thread:{0}", Thread.CurrentThread.ManagedThreadId); long result = 0; for (int i = 0; i < 1000000000; i++) { result += i; } Console.WriteLine("Asynchronous end, calculation result{0},thread {1}", result, Thread.CurrentThread.ManagedThreadId); }); t1.Start(); await t1; }
Comparison between async/await and ordinary asynchronous
Thinking: implement a program. After each task sleeps for 5 seconds, return to 100 and print 100
public static void DoSomething() { Console.WriteLine("Asynchronous method start 1"); var aaa= await Task.Run(() => { Thread.Sleep(5000); return 100; }); Console.WriteLine("Calculation results{0}", aaa.result); }
Call:
static void Main(string[] args) { DoSomething(); DoSomething(); DoSomething(); }
Explanation: after the above code is run, it is executed synchronously. Although the Task will generate a thread to run asynchronously, AAA needs to be used because of the return value in the Task Result acquisition blocks the thread, so the running results are synchronized.
Convert the above code to asynchronous:
public static void DoSomething111() { Console.WriteLine("Asynchronous method start 1"); //The results are obtained through the first asynchronous method var aaa= Task.Run(() => { Thread.Sleep(5000); return 100; }); aaa.ContinueWith(x => { Console.WriteLine(x.Result); }); }
Explanation: due to Task Run () returns a Task object, so if you don't want to block the thread, you can call ContinueWith for callback processing, and get the return value of the Task in the callback. ContinueWith won't block the main thread.
Elegant writing async/await:
public async static void DoSomething111() { Console.WriteLine("Asynchronous method start 1"); //The results are obtained through the first asynchronous method var aaa= await Task.Run(() => { Thread.Sleep(5000); return 100; }); Console.WriteLine("The result is{0}", aaa); }
Explanation: task Run () executes a time-consuming task. The await flag indicates waiting for the task result and assigning the result to aaa. Yes, it's so elegant.