Home >Backend Development >C#.Net Tutorial >Detailed explanation of graphic code of Thread, Task, Async/Await, IAsyncResult in C#
This article mainly introduces the relevant knowledge of Thread, Task, Async/Await, IAsyncResult in C#. It has a certain reference value, let’s take a look with the editor below
Speaking of asynchronous, Thread, Task, async/await, IAsyncResult, these things are definitely unavoidable. Let’s talk about them in turn today.
1. Thread
The meaning of multi-threading is that in an application, multiple execution parts can be executed at the same time; for more time-consuming operations ( For example, io, Database operations), or waiting for a response (such as WCF communication) The operation can be performed by starting the background thread separately, so that the main thread will not be blocked and can continue to execute; wait until the background thread is completed, then notify the main thread, and then make the corresponding operation!
In C#! It is relatively simple to start a new thread in
static void Main(string[] args) { Console.WriteLine("主线程开始"); //IsBackground=true,将其设置为后台线程 Thread t = new Thread(Run) { IsBackground = true }; t.Start(); Console.WriteLine("主线程在做其他的事!"); //主线程结束,后台线程会自动结束,不管有没有执行完成 //Thread.Sleep(300); Thread.Sleep(1500); Console.WriteLine("主线程结束"); } static void Run() { Thread.Sleep(700); Console.WriteLine("这是后台线程调用"); }
The execution result is as shown below,
You can see that after starting the background thread, the main thread continues to execute. It does not wait until the background thread is executed.
##1.1 Thread Pool
Imagine if there are a large number of tasks that need to be processed, such as the website background. For HTTP request processing, is it necessary to create a background thread for each request? It is obviously inappropriate. This will occupy a lot of memory, and the frequent creation process will also seriously affect the speed. So what should I do with the thread pool? In order to solve this problem, the created threads are stored to form a thread pool (with multiple threads in it). When a task is to be processed, if there are idle threads in the thread pool (after the previous task is completed, the thread will not be recycling, will be set to the idle state), then directly call the thread execution in the thread pool (for example, the Applicationobject in the asp.net processing mechanism),
Usage example:for (int i = 0; i < 10; i++) { ThreadPool.QueueUserWorkItem(m => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString()); }); } Console.Read();Running results: It can be seen that although it was executed 10 times, 10 threads were not created
#.
## 1.2 Semaphore Semaphore is responsible for coordinating threads and can limit the number of threads accessing a certain resource
Here is SemaphoreSlim A simple example of class usage:
static SemaphoreSlim semLim = new SemaphoreSlim(3); //3表示最多只能有三个线程同时访问 static void Main(string[] args) { for (int i = 0; i < 10; i++) { new Thread(SemaphoreTest).Start(); } Console.Read(); } static void SemaphoreTest() { semLim.Wait(); Console.WriteLine("线程" + Thread.CurrentThread.ManagedThreadId.ToString() + "开始执行"); Thread.Sleep(2000); Console.WriteLine("线程" + Thread.CurrentThread.ManagedThreadId.ToString() + "执行完毕"); semLim.Release(); }
The execution results are as follows:
It can be seen that only three threads are executing at the beginning , when a thread is executed and released, a new thread will execute the method!
In addition to the SemaphoreSlim class, you can also use the Semaphore class, which feels more flexible. If you are interested, you can search it. Demonstration is done!
2.TaskTask was added to .NET4.0. It has similar functions to the thread pool ThreadPool. When you use Task to start a new task, it will be drawn from the thread pool. Calling thread, and Thread will create a new thread every time it is instantiated.
Console.WriteLine("主线程启动"); //Task.Run启动一个线程 //Task启动的是后台线程,要在主线程中等待后台线程执行完毕,可以调用Wait方法 //Task task = Task.Factory.StartNew(() => { Thread.Sleep(1500); Console.WriteLine("task启动"); }); Task task = Task.Run(() => { Thread.Sleep(1500); Console.WriteLine("task启动"); }); Thread.Sleep(300); task.Wait(); Console.WriteLine("主线程结束");
The execution results are as follows:
Method to start a new task: Task.Run() or Task.Factory.StartNew(), which opens the background Thread
To wait in the main thread for the background thread to complete execution, you can use the Wait method (it will be executed in a synchronous manner). Without Wait, it will be executed asynchronously.
Compare Task and Thread:
static void Main(string[] args) { for (int i = 0; i < 5; i++) { new Thread(Run1).Start(); } for (int i = 0; i < 5; i++) { Task.Run(() => { Run2(); }); } } static void Run1() { Console.WriteLine("Thread Id =" + Thread.CurrentThread.ManagedThreadId); } static void Run2() { Console.WriteLine("Task调用的Thread Id =" + Thread.CurrentThread.ManagedThreadId); }
Execution result:
It can be seen that using Thread directly will open 5 threads. Use Task (using thread pool) to open 3!
2.1 Taskb54c2c292509147c0b54128f4eb90887##Taskb54c2c292509147c0b54128f4eb90887 is a Task with a return value, and TResult is the return value type.
Console.WriteLine("主线程开始"); //返回值类型为string Task<string> task = Task<string>.Run(() => { Thread.Sleep(2000); return Thread.CurrentThread.ManagedThreadId.ToString(); }); //会等到task执行完毕才会输出; Console.WriteLine(task.Result); Console.WriteLine("主线程结束");Running result:
The return value can be obtained through task.Result. If the background thread has not finished executing when the value is obtained, it will Wait for it to complete!
A brief mention: Task tasks can be canceled through the CancellationTokenSource class. I feel that it is not used much and the usage is relatively simple. If you are interested, you can search it!3. async/await
async/await was introduced in C# 5.0, first usage:
static void Main(string[] args) { Console.WriteLine("-------主线程启动-------"); Task<int> task = GetStrLengthAsync(); Console.WriteLine("主线程继续执行"); Console.WriteLine("Task返回的值" + task.Result); Console.WriteLine("-------主线程结束-------"); } static async Task<int> GetStrLengthAsync() { Console.WriteLine("GetStrLengthAsync方法开始执行"); //此处返回的<string>中的字符串类型,而不是Task<string> string str = await GetString(); Console.WriteLine("GetStrLengthAsync方法执行结束"); return str.Length; } static Task<string> GetString() { //Console.WriteLine("GetString方法开始执行") return Task<string>.Run(() => { Thread.Sleep(2000); return "GetString的返回值"; }); }async is used to modify methods , indicating that this method is asynchronous, and the return type of the declared method must be: void, Task or Taskb54c2c292509147c0b54128f4eb90887.
await必须用来修饰Task或Taskb54c2c292509147c0b54128f4eb90887,而且只能出现在已经用async关键字修饰的异步方法中。通常情况下,async/await成对出现才有意义,
看看运行结果:
可以看出来,main函数调用GetStrLengthAsync方法后,在await之前,都是同步执行的,直到遇到await关键字,main函数才返回继续执行。
那么是否是在遇到await关键字的时候程序自动开启了一个后台线程去执行GetString方法呢?
现在把GetString方法中的那行注释加上,运行的结果是:
大家可以看到,在遇到await关键字后,没有继续执行GetStrLengthAsync方法后面的操作,也没有马上反回到main函数中,而是执行了GetString的第一行,以此可以判断await这里并没有开启新的线程去执行GetString方法,而是以同步的方式让GetString方法执行,等到执行到GetString方法中的Task98c455a79ddfebb79781bff588e7b37e.Run()的时候才由Task开启了后台线程!
那么await的作用是什么呢?
可以从字面上理解,上面提到task.wait可以让主线程等待后台线程执行完毕,await和wait类似,同样是等待,等待Task98c455a79ddfebb79781bff588e7b37e.Run()开始的后台线程执行完毕,不同的是await不会阻塞主线程,只会让GetStrLengthAsync方法暂停执行。
那么await是怎么做到的呢?有没有开启新线程去等待?
只有两个线程(主线程和Task开启的线程)!至于怎么做到的(我也不知道......>_03065e15d4ebf3426e4f9cf8ae830fea:
List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 6, 7, 8, 9 }; Parallel.ForEach<int>(list, n => { Console.WriteLine(n); Thread.Sleep(1000); });
Action[] actions = new Action[] { new Action(()=>{ Console.WriteLine("方法1"); }), new Action(()=>{ Console.WriteLine("方法2"); }) }; Parallel.Invoke(actions);
The above is the detailed content of Detailed explanation of graphic code of Thread, Task, Async/Await, IAsyncResult in C#. For more information, please follow other related articles on the PHP Chinese website!