Home > Backend Development > C#.Net Tutorial > Detailed explanation of graphic code of Thread, Task, Async/Await, IAsyncResult in C#

Detailed explanation of graphic code of Thread, Task, Async/Await, IAsyncResult in C#

黄舟
Release: 2017-03-29 11:28:10
Original
3298 people have browsed it

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("这是后台线程调用");
}
Copy after login

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 Application

object 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();
Copy after login

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();
}
Copy after login

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.Task

Task 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("主线程结束");
Copy after login

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);
}
Copy after login

Execution result:

It can be seen that using Thread directly will open 5 threads. Use Task (using thread pool) to open 3!

2.1 Task##Task 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("主线程结束");
Copy after login

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的返回值";
 });
}
Copy after login

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 Task.

await必须用来修饰Task或Task,而且只能出现在已经用async关键字修饰的异步方法中。通常情况下,async/await成对出现才有意义,

看看运行结果:

可以看出来,main函数调用GetStrLengthAsync方法后,在await之前,都是同步执行的,直到遇到await关键字,main函数才返回继续执行。

那么是否是在遇到await关键字的时候程序自动开启了一个后台线程去执行GetString方法呢?

现在把GetString方法中的那行注释加上,运行的结果是:

大家可以看到,在遇到await关键字后,没有继续执行GetStrLengthAsync方法后面的操作,也没有马上反回到main函数中,而是执行了GetString的第一行,以此可以判断await这里并没有开启新的线程去执行GetString方法,而是以同步的方式让GetString方法执行,等到执行到GetString方法中的Task.Run()的时候才由Task开启了后台线程!

那么await的作用是什么呢?

可以从字面上理解,上面提到task.wait可以让主线程等待后台线程执行完毕,await和wait类似,同样是等待,等待Task.Run()开始的后台线程执行完毕,不同的是await不会阻塞主线程,只会让GetStrLengthAsync方法暂停执行。

那么await是怎么做到的呢?有没有开启新线程去等待?

只有两个线程(主线程和Task开启的线程)!至于怎么做到的(我也不知道......>_<),大家有兴趣的话研究下吧!

4.IAsyncResult

IAsyncResult自.NET1.1起就有了,包含可异步操作的方法的类需要实现它,Task类就实现了该接口

在不借助于Task的情况下怎么实现异步呢?

class Program
{
 static void Main(string[] args)
 {
  Console.WriteLine("主程序开始--------------------");
  int threadId;
  AsyncDemo ad = new AsyncDemo();
  AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

  IAsyncResult result = caller.BeginInvoke(3000,out threadId, null, null);
  Thread.Sleep(0);
  Console.WriteLine("主线程线程 {0} 正在运行.",Thread.CurrentThread.ManagedThreadId)
  //会阻塞线程,直到后台线程执行完毕之后,才会往下执行
  result.AsyncWaitHandle.WaitOne();
  Console.WriteLine("主程序在做一些事情!!!");
  //获取异步执行的结果
  string returnValue = caller.EndInvoke(out threadId, result);
  //释放资源
  result.AsyncWaitHandle.Close();
  Console.WriteLine("主程序结束--------------------");
  Console.Read();
 }
}
public class AsyncDemo
{
 //供后台线程执行的方法
 public string TestMethod(int callDuration, out int threadId)
 {
  Console.WriteLine("测试方法开始执行.");
  Thread.Sleep(callDuration);
  threadId = Thread.CurrentThread.ManagedThreadId;
  return String.Format("测试方法执行的时间 {0}.", callDuration.ToString());
 }
}
public delegate string AsyncMethodCaller(int callDuration, out int threadId);
Copy after login

关键步骤就是红色字体的部分,运行结果:

和Task的用法差异不是很大!result.AsyncWaitHandle.WaitOne()就类似Task的Wait。

5.Parallel

最后说一下在循环中开启多线程的简单方法:

Stopwatch watch1 = new Stopwatch();
watch1.Start();
for (int i = 1; i <= 10; i++)
{
 Console.Write(i + ",");
 Thread.Sleep(1000);
}
watch1.Stop();
Console.WriteLine(watch1.Elapsed);
Stopwatch watch2 = new Stopwatch();
watch2.Start();
//会调用线程池中的线程
Parallel.For(1, 11, i =>
{
 Console.WriteLine(i + ",线程ID:" + Thread.CurrentThread.ManagedThreadId);
 Thread.Sleep(1000);
});
watch2.Stop();
Console.WriteLine(watch2.Elapsed);
Copy after login

运行结果:

循环List

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);
});
Copy after login

执行Action[]数组里面的方法:

Action[] actions = new Action[] { 
 new Action(()=>{
  Console.WriteLine("方法1");
 }),
 new Action(()=>{
  Console.WriteLine("方法2");
 })
};
Parallel.Invoke(actions);
Copy after login

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!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template