집 >백엔드 개발 >C#.Net 튜토리얼 >C#의 Thread, Task, Async/Await, IAsyncResult 그래픽 코드에 대한 자세한 설명
이 글에서는 C#의 Thread, Task, Async/Await, IAsyncResult 관련 지식을 주로 소개합니다. 특정 참조 값이 있으므로 아래 편집기를 통해 살펴보겠습니다
비동기, 스레드, 태스크, async/await, IAsyncResult에 대해 말하자면 오늘은 확실히 피할 수 없는 것들에 대해 차례로 이야기하겠습니다
1. 스레드
멀티 스레딩의 의미는 애플리케이션에서 더 많은 시간이 소요되는 작업을 위해 여러 실행 부분을 동시에 실행할 수 있다는 것입니다. , io, 데이터베이스 작업 ) 또는 응답을 기다리는 중(예: WCF 통신) 백그라운드 스레드를 별도로 시작하여 작업을 수행할 수 있으므로 메인 스레드가 차단되지 않고 계속 실행할 수 있습니다. 백그라운드 스레드가 완료될 때까지 기다린 후 메인 스레드에 알리고 해당 작업을 수행합니다.
C#에서는
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("这是后台线程调用"); }
에서 새 스레드를 시작하는 것이 비교적 간단합니다. 실행 결과는 다음과 같습니다.
백그라운드 스레드가 시작된 후에도 메인 스레드가 계속 실행되는 것을 볼 수 있습니다.
1.1 스레드 풀
웹사이트 백그라운드 등 처리해야 할 작업이 많다고 상상해 보세요. HTTP 요청 처리를 위해 각 요청마다 백그라운드 스레드를 생성해야 하는 것은 당연합니다. 메모리를 많이 차지하며, 잦은 생성 프로세스도 속도에 심각한 영향을 미치게 되는데, 이 문제를 해결하려면 생성된 스레드를 저장하여 스레드 풀을 구성해야 합니다. 작업을 처리할 때 스레드 풀에 유휴 스레드가 있는 경우(이전 작업이 완료된 후 스레드는 재활용되지 않고 유휴 상태로 설정됨) 스레드 실행을 직접 호출합니다. 스레드 풀(예: asp.net 처리 메커니즘의 Application 개체 ),
사용 예:
for (int i = 0; i < 10; i++) { ThreadPool.QueueUserWorkItem(m => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString()); }); } Console.Read();
실행 결과 :
10번을 실행했는데도 10개의 스레드가 생성되지 않은 것을 볼 수 있습니다. 🎜>
1.2 세마포 Semaphore는 스레드 조정을 담당하며 특정 리소스에 액세스하는 스레드 수를 제한할 수 있습니다.
다음은 SemaphoreSlim에 대한 소개입니다. 클래스 사용의 간단한 예:
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(); }
실행 결과는 다음과 같습니다.
보시다시피 처음에는 스레드가 3개만 실행되고 스레드가 실행되고 해제되면 새로운 스레드가 생성됩니다.
SemaphoreSlim 클래스 외에도 좀 더 유연한 느낌의 Semaphore 클래스를 사용할 수도 있으니 관심이 있으시면 검색하시면 됩니다!
2.TaskTask는 .NET4.0에 추가되었습니다. Task를 사용하여 새 작업을 시작하면, 스레드 풀에서 그려지며 스레드는 인스턴스화될 때마다 새 스레드를 생성합니다.
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("主线程结束");
실행 결과는 다음과 같습니다.
새 작업을 시작하는 방법: Task.Run() 또는 Task.Factory.StartNew(), 백그라운드를 시작하는 스레드
가 백그라운드 스레드가 실행을 완료할 때까지 기본 스레드에서 기다리려는 경우 Wait 메서드를 사용할 수 있습니다(동기 방식으로 실행됩니다). Wait가 없으면 비동기적으로 실행됩니다.
Task와 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); }
실행 결과:
Thread를 직접 사용하면 5개의 Thread가 열리는 것을 볼 수 있습니다. 작업(스레드 풀 사용) 열기 3!
2.1 Taskb54c2c292509147c0b54128f4eb90887Taskb54c2c292509147c0b54128f4eb90887는 반환 값이 있는 Task이고 TResult는 반환 값 유형입니다.
Console.WriteLine("主线程开始"); //返回值类型为string Task<string> task = Task<string>.Run(() => { Thread.Sleep(2000); return Thread.CurrentThread.ManagedThreadId.ToString(); }); //会等到task执行完毕才会输出; Console.WriteLine(task.Result); Console.WriteLine("主线程结束");
실행 결과:
task.Result를 통해 반환 값을 얻을 수 있습니다. 값을 얻었을 때 백그라운드 스레드의 실행이 완료되지 않은 경우, 완료될 때까지 기다리세요!
간단한 언급:
CancellationTokenSource 클래스를 통해 작업을 취소할 수 있으며 많이 사용되지 않고 사용법도 비교적 간단하다고 생각됩니다. !
3. async/awaitasync/await는 C# 5.0에 도입되었으며 먼저 사용법은 다음과 같습니다.
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는 메서드를 수정하는 데 사용됩니다. 이는 이 메서드가 비동기식임을 나타내며 선언된 메서드의 반환 유형은 void, Task 또는 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);
위 내용은 C#의 Thread, Task, Async/Await, IAsyncResult 그래픽 코드에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!