Multithreading in C # mit Aufgaben

click fraud protection

Das Computerprogrammierung Der Begriff "Thread" steht für "Thread of Execution", bei dem ein Prozessor einem bestimmten Pfad durch Ihren Code folgt. Das Konzept, mehr als einem Thread gleichzeitig zu folgen, führt das Thema Multitasking und Multithreading ein.

Eine Anwendung enthält einen oder mehrere Prozesse. Stellen Sie sich einen Prozess als ein Programm vor, das auf Ihrem Computer ausgeführt wird. Jetzt hat jeder Prozess einen oder mehrere Threads. Eine Spieleanwendung verfügt möglicherweise über einen Thread zum Laden von Ressourcen von der Festplatte, einen anderen zum Ausführen von KI und einen anderen zum Ausführen des Spiels als Server.

In .NET / Windows weist das Betriebssystem einem Thread Prozessorzeit zu. Jeder Thread verfolgt die Ausnahmebehandlungsroutinen und die Priorität, mit der er ausgeführt wird, und kann den Thread-Kontext bis zur Ausführung speichern. Der Thread-Kontext ist die Information, die der Thread wieder aufnehmen muss.

Multitasking mit Threads

Threads beanspruchen etwas Speicherplatz und das Erstellen dauert ein wenig. Daher möchten Sie normalerweise nicht viele verwenden. Denken Sie daran, sie konkurrieren um die Prozessorzeit. Wenn Ihr Computer über mehrere CPUs verfügt, führt Windows oder .NET möglicherweise jeden Thread auf einer anderen CPU aus Es laufen mehrere Threads auf derselben CPU, dann kann immer nur einer aktiv sein und das Wechseln der Threads dauert Zeit.

instagram viewer

Die CPU führt einen Thread für einige Millionen Anweisungen aus und wechselt dann zu einem anderen Thread. Alle CPU-Register, der aktuelle Programmausführungspunkt und der Stapel müssen für den ersten Thread irgendwo gespeichert und dann für den nächsten Thread von einem anderen Ort wiederhergestellt werden.

Thread erstellen

Im Namespace System. Einfädelnfinden Sie den Thread-Typ. Der Konstruktor-Thread (ThreadStart) erstellt eine Instanz eines Threads. In jüngster Zeit jedoch C # Code, es ist wahrscheinlicher, einen Lambda-Ausdruck zu übergeben, der die Methode mit beliebigen Parametern aufruft.

Wenn Sie sich nicht sicher sind Lambda-AusdrückeEs könnte sich lohnen, LINQ zu testen.

Hier ist ein Beispiel für einen Thread, der erstellt und gestartet wird:

using System;
mit System. Einfädeln;
Namespace ex1
{
Klassenprogramm
{
public static void Write1 ()
{
Konsole. Schreiben ('1');
Faden. Schlaf (500);
}
statische Leere Main (string [] args)
{
var task = neuer Thread (Write1);
Aufgabe. Start() ;
für (var i = 0; i <10; i ++)
{
Konsole. Schreiben ('0');
Konsole. Schreiben (Aufgabe. Ist am Leben? 'ANZEIGE') ;
Faden. Schlaf (150);
}
Konsole. Schlüssel einlesen() ;
}
}
}

In diesem Beispiel wird lediglich "1" in die Konsole geschrieben. Der Haupt-Thread schreibt 10 Mal eine "0" in die Konsole, gefolgt von einem "A" oder "D", je nachdem, ob der andere Thread noch aktiv oder tot ist.

Der andere Thread wird nur einmal ausgeführt und schreibt eine "1". Nach der Verzögerung von einer halben Sekunde im Thread Write1 () wird der Thread beendet und die Aufgabe ausgeführt. IsAlive in der Hauptschleife gibt jetzt "D" zurück.

Thread-Pool und Task Parallel Library

Verwenden Sie einen Thread-Pool, anstatt einen eigenen Thread zu erstellen, es sei denn, Sie müssen dies wirklich tun. Ab .NET 4.0 haben wir Zugriff auf die Task Parallel Library (TPL). Wie im vorherigen Beispiel brauchen wir wieder ein bisschen LINQ, und ja, es sind alles Lambda-Ausdrücke.

Aufgaben verwendet die Thread-Pool hinter den Kulissen, aber nutzen Sie die Threads je nach verwendeter Anzahl besser.

Das Hauptobjekt in der TPL ist eine Aufgabe. Dies ist eine Klasse, die eine asynchrone Operation darstellt. Der häufigste Weg, um Dinge zum Laufen zu bringen, ist die Aufgabe. Fabrik. StartNeu wie in:

Aufgabe. Fabrik. StartNew (() => DoSomething ());

Wobei DoSomething () die ausgeführte Methode ist. Es ist möglich, eine Aufgabe zu erstellen und nicht sofort ausführen zu lassen. Verwenden Sie in diesem Fall einfach die folgende Aufgabe:

var t = new Task (() => Konsole. WriteLine ("Hallo"));
...
t. Start();

Das startet den Thread erst, wenn .Start () aufgerufen wird. Im folgenden Beispiel sind fünf Aufgaben aufgeführt.

using System;
mit System. Einfädeln;
mit System. Einfädeln. Aufgaben;
Namespace ex1
{
Klassenprogramm
{
public static void Write1 (int i)
{
Konsole. Schreibe ich) ;
Faden. Schlaf (50);
}
statische Leere Main (string [] args)
{
für (var i = 0; i <5; i ++)
{
var value = i;
var runningTask = Aufgabe. Fabrik. StartNew (() => Write1 (Wert));
}
Konsole. Schlüssel einlesen() ;
}
}
}

Wenn Sie dies ausführen, werden die Ziffern 0 bis 4 in zufälliger Reihenfolge ausgegeben, z. B. 03214. Dies liegt daran, dass die Reihenfolge der Aufgabenausführung von .NET festgelegt wird.

Sie fragen sich vielleicht, warum der var-Wert = i benötigt wird. Wenn Sie es entfernen und Write (i) aufrufen, wird etwas Unerwartetes wie 55555 angezeigt. Warum ist das? Dies liegt daran, dass die Aufgabe den Wert von i zum Zeitpunkt der Ausführung der Aufgabe anzeigt und nicht zum Zeitpunkt der Erstellung der Aufgabe. Durch das Erstellen eines neuen Variable Jedes Mal in der Schleife wird jeder der fünf Werte korrekt gespeichert und erfasst.

instagram story viewer