Warteschlangen und Hintergrundaufgaben in C#: So beschleunigen Sie Ihre Anwendung ohne Schmerz

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Warum Ihre C#-Anwendung Warteschlangen und Hintergrundaufgaben benötigt?

\n\n

Stellen Sie sich vor: Sie starten eine Webanwendung in C#, der Benutzer klickt auf die Schaltfläche „Bericht senden“, und … der Server hängt für 30 Sekunden, während ein PDF generiert wird. Kommt Ihnen bekannt vor? Im Jahr 2024 verzeihen Benutzer keine Verzögerungen. Die Lösung: Warteschlangen und Hintergrundaufgaben. Sie verwandeln synchrone Hölle in asynchrones Paradies.

\n\n

In diesem Artikel analysieren wir, wie Sie die Hintergrundverarbeitung in C# richtig organisieren: von integrierten Channel<T> bis hin zu industriellem RabbitMQ. Sie erfahren, wie Sie schwere Arbeit aus dem Hauptthread auslagern, ohne die Architektur zu beschädigen. Los geht's!

\n\n

Was ist eine Aufgabenwarteschlange und warum wird sie in C# benötigt?

\n\n

Eine Warteschlange (Queue) ist eine FIFO-Datenstruktur (First In, First Out). Im Kontext von C# ist dies ein Mechanismus, der es ermöglicht, die Ausführung einer Aufgabe zu verschieben, um den Hauptthread nicht zu blockieren. Eine Hintergrundaufgabe ist Code, der „hinter den Kulissen“ ausgeführt wird, während der Benutzer weiterhin auf der Website klickt.

\n\n

Typische Szenarien:

\n
    \n
  • Versand von E-Mail-Benachrichtigungen (100 E-Mails = 100 Anfragen an SMTP)
  • \n
  • Generierung von Berichten und Excel-Dateien
  • \n
  • Verarbeitung hochgeladener Bilder (Größenänderung, Wasserzeichen)
  • \n
  • Integration mit externen APIs (langsame Antworten)
  • \n
  • Protokollierung in die Datenbank (um die UI nicht zu verlangsamen)
  • \n
\n\n

Ohne Warteschlangen wird die C#-Anwendung bei jeder schweren Anfrage „einfrieren“. Mit Warteschlangen legen Sie die Aufgabe einfach in einen Puffer und antworten dem Benutzer: „Erledigt, wir verarbeiten es.“

\n\n

Variante 1: Hintergrundaufgaben mit BackgroundService (integriert in .NET)

\n\n

Der einfachste Weg ist die Verwendung von BackgroundService aus Microsoft.Extensions.Hosting. Dies ist eine Basisklasse für die Erstellung von Hintergrunddiensten in ASP.NET Core. Sie eignet sich ideal für einfache Szenarien, bei denen keine komplexe Nachrichtenweiterleitung erforderlich ist.

\n\n

Beispiel: Hintergrundverarbeiter mit Channel<T>

\n\n

Schreiben wir einen einfachen Producer-Consumer. Der Producer (Controller) legt eine Aufgabe in den Kanal, der Consumer (BackgroundService) holt sie ab und führt sie aus.

\n\n
// Schritt 1. Kanal erstellen (threadsichere Warteschlange)\npublic class TaskChannel\n{\n    private readonly Channel<string> _channel = \n        Channel.CreateBounded<string>(new BoundedChannelOptions(100)\n        {\n            FullMode = BoundedChannelFullMode.Wait\n        });\n\n    public ChannelWriter<string> Writer => _channel.Writer;\n    public ChannelReader<string> Reader => _channel.Reader;\n}\n\n// Schritt 2. BackgroundService, der aus dem Kanal liest\npublic class EmailBackgroundService : BackgroundService\n{\n    private readonly TaskChannel _taskChannel;\n\n    public EmailBackgroundService(TaskChannel taskChannel)\n    {\n        _taskChannel = taskChannel;\n    }\n\n    protected override async Task ExecuteAsync(CancellationToken stoppingToken)\n    {\n        await foreach (var emailData in _taskChannel.Reader.ReadAllAsync(stoppingToken))\n        {\n            // Simulation des E-Mail-Versands (2 Sekunden)\n            await Task.Delay(2000, stoppingToken);\n            Console.WriteLine($"E-Mail gesendet: {emailData}");\n        }\n    }\n}\n\n// Schritt 3. Controller, der Aufgaben ablegt\n[ApiController]\n[Route("api/email")]\npublic class EmailController : ControllerBase\n{\n    private readonly TaskChannel _taskChannel;\n\n    public EmailController(TaskChannel taskChannel)\n    {\n        _taskChannel = taskChannel;\n    }\n\n    [HttpPost("send")]\n    public IActionResult SendEmail([FromBody] string emailData)\n    {\n        _taskChannel.Writer.TryWrite(emailData);\n        return Accepted(new { message = "E-Mail in die Warteschlange gestellt" });\n    }\n}\n\n// Schritt 4. Registrierung in Program.cs\nbuilder.Services.AddSingleton<TaskChannel>();\nbuilder.Services.AddHostedService<EmailBackgroundService>();
\n\n

Was passiert hier? Der Benutzer ruft POST /api/email/send auf – die Daten gelangen in den Ka

Blogs

Buchempfehlungen