Heim  >  Artikel  >  Backend-Entwicklung  >  Detaillierte Erläuterung des grafischen Codes von Thread, Task, Async/Await, IAsyncResult in C#

Detaillierte Erläuterung des grafischen Codes von Thread, Task, Async/Await, IAsyncResult in C#

黄舟
黄舟Original
2017-03-29 11:28:103239Durchsuche

In diesem Artikel werden hauptsächlich die relevanten Kenntnisse zu Thread, Task, Async/Await und IAsyncResult in C# vorgestellt. Es hat einen gewissen Referenzwert, werfen wir einen Blick mit dem Editor unten

Apropos asynchron, Thread, Task, async/await, IAsyncResult, diese Dinge sind heute definitiv unvermeidlich

1. Thread

Die Bedeutung von Multithreading besteht darin, dass in einer Anwendung mehrere Ausführungsteile gleichzeitig ausgeführt werden können ( Für Beispiel: io, Datenbankoperationen ) oder das Warten auf eine Antwort (z. B als WCF-Kommunikation) Der Vorgang kann durch separates Starten des Hintergrundthreads ausgeführt werden, sodass der Hauptthread nicht blockiert wird und weiter ausgeführt werden kann. Warten Sie, bis der Hintergrundthread abgeschlossen ist, benachrichtigen Sie dann den Hauptthread und führen Sie dann die entsprechenden Schritte aus Operation

in C#! Es ist relativ einfach, einen neuen 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("这是后台线程调用");
}

zu starten. Das Ausführungsergebnis ist wie folgt:

Sie können sehen, dass nach dem Starten des Hintergrundthreads der Hauptthread weiterhin ausgeführt wird

1.1 Thread Pool

Stellen Sie sich vor, es gäbe einen Ist es für die Verarbeitung von HTTP-Anfragen im Hintergrund der Website erforderlich, für jede Anfrage einen Hintergrund-Thread zu erstellen? Dies ist offensichtlich ungeeignet Der häufige Erstellungsprozess wirkt sich auch erheblich auf die Geschwindigkeit aus. Der Zweck des Pools besteht darin, einen Thread-Pool zu bilden (mit mehreren Threads darin). Zur Verarbeitung gilt: Wenn sich im Thread-Pool inaktive Threads befinden (nach Abschluss der vorherigen Aufgabe wird der Thread nicht recycelt und in den Leerlaufzustand versetzt), rufen Sie dann direkt die Thread-Ausführung im Thread-Pool auf (z. B. das Application-Objekt im asp.net-Verarbeitungsmechanismus),

Verwendungsbeispiel:

for (int i = 0; i < 10; i++)
{
 ThreadPool.QueueUserWorkItem(m =>
 {
  Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
 });
}
Console.Read();

Laufergebnis:

Sie können sehen, dass, obwohl es 10 Mal ausgeführt wurde, 10 Threads nicht erstellt wurden

1.2 Semaphore

Semaphore ist für die Koordination von Threads verantwortlich und kann die Anzahl der Threads begrenzen, die auf eine bestimmte Ressource zugreifen

Hier ist ein einfaches Beispiel für die Verwendung der SemaphoreSlim-Klasse:

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

Die Ausführung Die Ergebnisse lauten wie folgt:

Wie Sie sehen können, werden am Anfang nur drei Threads ausgeführt. Wenn ein Thread ausgeführt und freigegeben wird, gibt es einen Neuer Thread zum Ausführen der Methode.

Zusätzlich zur Semaphore-Klasse können Sie auch die Semaphore-Klasse verwenden, die sich flexibler anfühlt. Sie können sie durchsuchen. Hier wird es keine Demonstration geben.

2.Task

Task wurde in .NET4.0 hinzugefügt. Es verfügt über ähnliche Funktionen wie der Thread-Pool ThreadPool. Es wird aus dem Thread-Pool des aufrufenden Threads gezogen und Thread erstellt bei jeder Instanziierung einen neuen Thread.

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

Die Ausführungsergebnisse lauten wie folgt:

Methode zum Starten einer neuen Aufgabe: Task.Run() oder Task.Factory.StartNew( ), open Es ist ein Hintergrundthread

Um darauf zu warten, dass der Hintergrundthread die Ausführung im Hauptthread abschließt, können Sie die Wait-Methode verwenden (sie wird synchron ausgeführt). Ohne Warten wird es asynchron ausgeführt.

Aufgabe und Thread vergleichen:

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);
}

Ausführungsergebnis:

Es ist ersichtlich, dass die direkte Verwendung von Thread 5 Threads öffnet , 3 mit Task geöffnet (unter Verwendung des Thread-Pools)!

2.1 Taskb54c2c292509147c0b54128f4eb90887

Taskb54c2c292509147c0b54128f4eb90887 ist eine Aufgabe mit einem Rückgabewert und TResult ist der Rückgabewerttyp.

Console.WriteLine("主线程开始");
//返回值类型为string
Task<string> task = Task<string>.Run(() => {
 Thread.Sleep(2000); 
 return Thread.CurrentThread.ManagedThreadId.ToString(); 
});
//会等到task执行完毕才会输出;
Console.WriteLine(task.Result);
Console.WriteLine("主线程结束");

Laufendes Ergebnis:

Der Rückgabewert kann über task.Result abgerufen werden, wenn die Ausführung des Hintergrundthreads zum Zeitpunkt des Werts noch nicht abgeschlossen ist erhalten, Es wird auf den Abschluss seiner Ausführung warten!

Eine kurze Erwähnung:

Aufgabenaufgaben können über die Klasse CancellationTokenSource abgebrochen werden. Ich habe das Gefühl, dass sie nicht häufig verwendet wird und die Verwendung relativ einfach ist. Wenn Sie interessiert sind, können Sie sie durchsuchen !

3. async/await

async/await wurde in C# 5.0 eingeführt, erste Verwendung:

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 wird verwendet. Ändern Sie die Methode um anzugeben, dass die Methode asynchron ist. Der Rückgabetyp der deklarierten Methode muss sein: void, Task oder 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[]数组里面的方法:

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

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des grafischen Codes von Thread, Task, Async/Await, IAsyncResult in C#. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn