C# wartet auf mehrere Aufgaben

Naila Saad Siddiqui 15 Februar 2024
  1. Synchrone und asynchrone Programmierung in C#
  2. Implementieren Sie die async-Methode und erwarten Sie mehrere Aufgaben in C#
C# wartet auf mehrere Aufgaben

Dieser triviale Leitfaden behandelt das asynchrone Programmiermodell und erklärt die zugehörigen Schlüsselwörter wie async, await und Task. Es demonstriert insbesondere das Konzept des Wartens auf mehrere Aufgaben mit C#.

Bevor wir uns dem eigentlichen Thema zuwenden, müssen wir kurz die Unterschiede zwischen synchronen und asynchronen Programmiermodellen überblicken. Also lasst uns anfangen!

Synchrone und asynchrone Programmierung in C#

Synchrone und asynchrone Modelle sind bei der Computerprogrammierung von entscheidender Bedeutung. Die Terminologien geben Auskunft über die Funktionen der einzelnen Programmiermodelle und deren Unterscheidungen.

Synchrone Tasks werden normalerweise in sequentieller Reihenfolge nacheinander ausgeführt. Asynchrone Aufgaben können gleichzeitig (in beliebiger Reihenfolge) ausgeführt werden.

Synchrone Programmierung in C#

Synchron ist eine blockierende Architektur, die am besten für reaktive Programmiersysteme geeignet ist. Als Single-Thread-Modell hält es sich an einen starren Satz von Sequenzen, sodass jede Operation einzeln und in präziser Abfolge ausgeführt wird.

Anweisungen für weitere Vorgehensweisen sind während der Durchführung eines Prozesses gesperrt. Die Erledigung einer Aufgabe beginnt mit der nächsten und so weiter.

Betrachten Sie ein Walkie-Talkie-Beispiel, um zu verstehen, wie die synchrone Programmierung funktioniert.

Eine Person spricht während eines Telefongesprächs, während die andere zuhört. Die zweite Person antwortet normalerweise sofort, nachdem die erste Person zu Ende gesprochen hat.

Betrachten wir in Bezug auf die Programmierung das folgende Beispiel, um die synchrone Programmierung zu verstehen:

using System;
using System.Threading;
public class Program {
  public static void Main(string[] args) {
    Process1();
    Process2();
  }
  static void Process1() {
    Console.WriteLine("Process 1 started");
    // You can write some code here that can take a longer time
    Thread.Sleep(5000);  // holing on execution for 5 sec
    Console.WriteLine("Process 1 Completed");
  }
  static void Process2() {
    Console.WriteLine("Process 2 Started");
    // write some code here that takes relatively less time
    Console.WriteLine("Process 2 Completed");
  }
}

Die Methode Process1() im obigen Beispiel wird verwendet, um einen langwierigen Prozess durchzuführen, z. B. das Lesen einer Datei vom Server, das Kontaktieren einer Web-API, die viele Daten zurückgibt, oder das Hoch- oder Herunterladen einer riesigen Datei.

Das Ausführen dauert etwas länger (zur Veranschaulichung hält Thread.Sleep(5000) es für 5 Sekunden). Die Methode process2() folgt der Methode Process1() und startet nicht gleichzeitig.

Das obige Programm läuft synchron. Es zeigt an, dass die Ausführung mit der Funktion Main() beginnt, wonach die Methode Process1() und die Methode Process2() jeweils der Reihe nach (d. h. streng nacheinander) ausgeführt werden.

Eine Anwendung wird während der Ausführung angehalten und reagiert nicht mehr (siehe Ausgabebildschirm unten). Die synchrone Programmierung wartet darauf, mit der nächsten Zeile fortzufahren, bis die vorherige Zeile ihre Ausführung beendet hat.

Schauen wir uns die Ausgabe an, um die synchrone Programmierung vollständig zu verstehen.

Ausgabe der synchronen Programmierung

Sie können der obigen Ausgabe entnehmen, dass die Ausführung blockiert ist, während auf den Abschluss von Process1 gewartet wird. Sobald seine Ausführung abgeschlossen ist, wird Process2 ausgeführt.

Asynchrone Programmierung in C#

Andererseits ist die asynchrone Programmierung ein Multithread-Stil, der am besten für Netzwerke und Kommunikation geeignet ist. Als nicht blockierendes Design verhindert die asynchrone Architektur nicht die nachfolgende Ausführung, während eine oder mehrere Operationen ausgeführt werden.

Bei der asynchronen Programmierung können mehrere verwandte Vorgänge gleichzeitig ausgeführt werden, ohne dass auf den Abschluss anderer Aktionen gewartet werden muss. Anstatt sofort nach Erhalt einer Nachricht zu antworten, warten Personen, die an asynchroner Kommunikation beteiligt sind, bis es bequem oder machbar ist, bevor sie sie lesen und verarbeiten.

Asynchrone Kommunikationstechniken umfassen SMS. Eine Person kann eine Textnachricht senden, und der Empfänger kann antworten, wann immer er möchte. Während er auf eine Antwort wartet, kann der Absender andere Aktionen ausführen.

Gemäss dem oben diskutierten Beispiel wird beispielsweise die Methode Process1() in einem anderen Thread als dem Thread-Pool im asynchronen Programmiermodell ausgeführt. Im Gegensatz dazu fährt der Hauptanwendungsthread mit der Ausführung der nachfolgenden Anweisung fort.

Microsoft empfiehlt die Verwendung des aufgabenbasierten asynchronen Musters bei der Implementierung asynchroner Programmierung in .NET Framework- oder .NET Core-Anwendungen mit den Schlüsselwörtern async und await und der Klasse Task oder Task<TResult>.

Lassen Sie uns den vorherigen Code mit asynchroner Programmierung umschreiben:

using System;
using System.Threading.Tasks;

public class Program {
  public static async Task Main(string[] args) {
    Process1();
    Process2();
    Console.ReadKey();
  }

  public static async void Process1() {
    Console.WriteLine("Process 1 Started");
    await Task.Delay(5000);  // holding execution for 5 seconds
    Console.WriteLine("Process 1 Completed");
  }
  static void Process2() {
    Console.WriteLine("Process 2 Started");
    // Write code here
    Console.WriteLine("Process 2 Completed");
  }
}

Das Schlüsselwort async wird verwendet, um die Methode Main() im obigen Beispiel zu identifizieren, und Task ist der Rückgabetyp.

Die Methode wird durch das Schlüsselwort async als asynchron gekennzeichnet. Denken Sie daran, dass jede Methode in der Methodenkette async sein muss, um eine asynchrone Programmierung durchzuführen.

Um also untergeordnete Methoden asynchron zu machen, muss die Funktion Main() async sein.

Das Schlüsselwort async markiert die Methode Process1() als asynchron und wartet auf Task.Delay(5000); verhindert, dass der Thread für 5 Sekunden etwas Nützliches ausführt.

Die Methode async Main() des Hauptanwendungs-Threads initiiert nun die Ausführung des Programms. Der Hauptanwendungsthread fährt mit der Ausführung der nachfolgenden Anweisung fort, die die Methode Process2() verwendet, ohne auf die Beendigung von async Process1() zu warten.

Die Ausgabe dieses Codesegments lautet:

Ausgabe der asynchronen Programmierung

Verwendung der Schlüsselwörter async, await und Task

Wenn die Methode async einen Wert an den aufrufenden Code zurückgibt, verwenden Sie async zusammen mit await und Task. Im obigen Beispiel haben wir das Schlüsselwort async verwendet, um zu zeigen, wie eine grundlegende asynchrone void-Methode verwendet wird.

Bevor die Methode async einen Wert zurückgibt, wartet das Schlüsselwort await darauf. Infolgedessen bleibt der Hauptanwendungsthread dort hängen, bis er einen Rückgabewert erhält.

Die Task-Klasse stellt eine asynchrone Operation dar, und ein Prozess, der ein Ergebnis zurückgeben kann, wird durch den generischen Typ Task<TResult> dargestellt. Im obigen Fall wurde await Task verwendet. await behält einen Thread für 5 Sekunden bei, nachdem Delay(5000) eine async-Operation gestartet hat, die für 5 Sekunden schläft.

Die Methode async gibt im folgenden Beispiel einen Wert zurück.

Implementieren Sie die async-Methode und erwarten Sie mehrere Aufgaben in C#

Stellen Sie sich ein Beispiel vor, in dem wir zwei Prozesse haben, von denen jeder einen Wert zurückgibt, und diese Werte an eine andere Funktion übergeben werden, die die Summe dieser beiden berechnet (Summe wird zur Veranschaulichung berechnet, Sie können jede Operation mit den Ergebnissen ausführen).

Zu diesem Zweck müssen wir warten, bis die Prozesse abgeschlossen sind und den Wert zurückgeben, und dann diese zurückgegebenen Werte an die andere Funktion übergeben. Dabei wird die Methode WhenAll verwendet.

Die Methode WhenAll wartet, bis alle Prozesse abgeschlossen sind, und speichert dann die zurückgegebenen Ergebnisse. Dies wird im folgenden Beispiel demonstriert:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

public class Program {
  static async Task Main(string[] args) {
    Task<int> res1 = Process1();
    Task<int> res2 = Process2();

    Console.WriteLine("After two processes.");
    var ls = await Task.WhenAll(res1, res2);
    DoSomeTask(ls);

    Console.ReadKey();
  }

  static async Task<int> Process1() {
    Console.WriteLine("Process 1 Started");
    await Task.Delay(5000);  // hold execution for 5 seconds
    Console.WriteLine("Process 1 Completed");
    return 15;
  }

  static async Task<int> Process2() {
    Console.WriteLine("Process 2 Started");
    await Task.Delay(3000);  // hold execution for 3 seconds
    Console.WriteLine("Process 2 Completed");
    return 25;
  }

  static void DoSomeTask(int[] l) {
    int sum = 0;
    foreach (int i in l) sum += i;
    Console.WriteLine("sum of the list is: {0} ", sum);
  }
}

Im obigen Codesegment haben wir zwei Funktionen erstellt, Process1 und Process2. Beide Funktionen haben eine Verzögerung von 5 Sekunden und 3 Sekunden.

Wenn die beiden Prozesse abgeschlossen sind, übergeben wir die zurückgegebenen Werte an DoSomeTask,, wo wir die Summe dieser Zahlen berechnen und auf dem Bildschirm anzeigen. Die Ausgabe dieses Codesegments lautet:

Asynchrone Programmierung mit Rückgabewerten