Big-Data-Verarbeitung mit C#: Von LINQ bis zu parallelen Threads

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 C# Ihr geheimes Werkzeug für Big Data ist?

\n\n

Wenn es um die Verarbeitung großer Datenmengen geht, kommen einem sofort Python mit seinen Pandas, Scala mit Spark oder Java mit Hadoop in den Sinn. Aber seien wir ehrlich: C# bleibt oft zu Unrecht im Schatten. Und das zu Unrecht. Die .NET-Plattform bietet uns so leistungsstarke Werkzeuge wie PLINQ, MemoryMappedFile, Parallel.For und asynchrone Streams, mit denen wir Gigabytes an Daten auf normaler Hardware verarbeiten können, ohne großen Aufwand.

\n\n

In diesem Artikel werden wir keine Theorie verbreiten – wir kommen sofort zur Sache. Sie erfahren, wie Sie das Maximum aus Ihrer CPU bei der Big-Data-Verarbeitung mit C# herausholen, wie Sie einen OutOfMemoryException vermeiden und wie Sie Dateien mit einer Größe von Dutzenden Gigabytes verarbeiten, als wären sie nur ein großes Buch.

\n\n

Das Hauptproblem: Wie vermeidet man Speicherüberlastung?

\n\n

Stellen Sie sich vor: Sie haben eine 50 GB große CSV-Datei mit Server-Logs. Sie öffnen sie mit einem normalen StreamReader und lesen sie zeilenweise. Alles gut? Nein. Wenn Sie versuchen, sie vollständig in eine List<string> zu laden – hallo, OutOfMemoryException. Selbst wenn Sie 64 GB RAM haben, kann .NET den Speicher so fragmentieren, dass ein großes Objekt einfach nicht in den Heap passt.

\n\n

Lösung Nummer eins: Streaming und Chunking. Laden Sie nicht alles auf einmal – verarbeiten Sie es häppchenweise.

\n\n
public async IAsyncEnumerable<string[]> ReadCsvChunksAsync(string filePath, int chunkSize = 10000)\n{\n    using var reader = new StreamReader(filePath);\n    string? line;\n    var buffer = new List<string>(chunkSize);\n\n    while ((line = await reader.ReadLineAsync()) != null)\n    {\n        buffer.Add(line);\n        if (buffer.Count >= chunkSize)\n        {\n            yield return buffer.ToArray();\n            buffer.Clear();\n        }\n    }\n\n    if (buffer.Count > 0)\n        yield return buffer.ToArray();\n}\n
\n\n

Jetzt können Sie Gigabytes verarbeiten, ohne an den Speicher zu denken:

\n\n
await foreach (var chunk in ReadCsvChunksAsync("logs.csv"))\n{\n    ProcessChunk(chunk); // Ihre Logik\n}\n
\n\n

Parallele Verarbeitung: Alle Prozessorkerne nutzen

\n\n

Gut, wir lesen die Daten in Portionen. Aber wenn Sie einen 16-Kern-Prozessor haben und die Daten sequenziell verarbeitet werden – nutzen Sie nur 6% seiner Leistung. Zeit, parallele Berechnungen mit C# einzuschalten.

\n\n

PLINQ – Parallel LINQ

\n\n

Die einfachste Magie ist das Hinzufügen von .AsParallel() zu Ihrer LINQ-Abfrage. Aber bei großen Datenmengen muss man vorsichtig sein: PLINQ entscheidet selbst, wann parallelisiert wird, was zu übermäßiger Fragmentierung führen kann.

\n\n
var numbers = Enumerable.Range(1, 10_000_000);\n\n// Normales LINQ (langsam)\nvar sum = numbers.Where(n => n % 2 == 0).Sum();\n\n// PLINQ (schnell, aber vorsichtig)\nvar parallelSum = numbers\n    .AsParallel()\n    .WithDegreeOfParallelism(Environment.ProcessorCount)\n    .Where(n => n % 2 == 0)\n    .Sum();\n\nConsole.WriteLine($"Ergebnis: {parallelSum}");\n
\n\n

Aber PLINQ ist kein Allheilmittel. Für komplexe Big-Data-Verarbeitung mit C# ist es besser, Parallel.ForEach mit manueller Aufteilungssteuerung zu verwenden.

\n\n

Parallel.ForEach mit Bereichsaufteilung

\n\n
var allLines = File.ReadLines("huge_dataset.csv");\nvar processedCount = 0;\nvar lockObject = new object();\n\nParallel.ForEach(\n    allLines,\n    new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },\n    line =>\n    {\n        var result = ProcessLine(line); // Ihre schwere Funktion\n        lock (lockObject)\n        {\n            processedCount++;\n            if (processedCount % 100_000 == 0)\n                Console.WriteLine($"Verarbeitet: {processedCount}");\n        }\n    });\n
\n\n

MemoryMappedFile: Mit Dateien wie mit Arbeitsspeicher arbeiten

\n\n

Wenn die Datei zu groß zum Laden in den RAM ist, Sie aber dennoch

Blogs

Buchempfehlungen