Traitement des mégadonnées en C# : de LINQ aux flux parallèles

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Pourquoi C# est votre outil secret pour le Big Data ?

\n\n

Quand il s'agit de traiter des mégadonnées, on pense immédiatement à Python avec ses Pandas, Scala avec Spark ou Java avec Hadoop. Mais soyons honnêtes : C# reste souvent injustement dans l'ombre. Et c'est dommage. La plateforme .NET nous offre des outils aussi puissants que PLINQ, MemoryMappedFile, Parallel.For et les flux asynchrones, qui permettent de traiter des gigaoctets de données sur du matériel classique sans acrobaties.

\n\n

Dans cet article, nous n'allons pas faire de théorie — nous passons directement à l'action. Vous apprendrez à tirer le meilleur parti de votre processeur lors du traitement des mégadonnées en C#, comment éviter un OutOfMemoryException et comment traiter des fichiers de plusieurs dizaines de gigaoctets comme s'il s'agissait simplement d'un gros livre.

\n\n

Le problème principal : comment ne pas saturer la mémoire ?

\n\n

Imaginez : vous avez un fichier CSV de 50 Go contenant des logs de serveur. Vous l'ouvrez avec un StreamReader classique et lisez ligne par ligne. Tout va bien ? Non. Si vous essayez de le charger entièrement dans un List<string> — bonjour OutOfMemoryException. Même avec 64 Go de RAM, .NET peut fragmenter la mémoire au point qu'un gros objet ne tienne tout simplement pas dans le tas.

\n\n

Solution numéro un : le streaming et le découpage en morceaux. Ne chargez pas tout d'un coup — mâchez par petits morceaux.

\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

Vous pouvez désormais traiter des gigaoctets sans vous soucier de la mémoire :

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

Traitement parallèle : utilisons tous les cœurs du processeur

\n\n

D'accord, nous lisons les données par lots. Mais si vous avez un processeur 16 cœurs et que les données sont traitées séquentiellement — vous n'utilisez que 6 % de sa puissance. Il est temps d'activer les calculs parallèles en C#.

\n\n

PLINQ — Parallel LINQ

\n\n

La magie la plus simple consiste à ajouter .AsParallel() à votre requête LINQ. Mais avec les mégadonnées, il faut être prudent : PLINQ décide lui-même quand paralléliser, ce qui peut entraîner une fragmentation excessive.

\n\n
var numbers = Enumerable.Range(1, 10_000_000);\n\n// LINQ classique (lent)\nvar sum = numbers.Where(n => n % 2 == 0).Sum();\n\n// PLINQ (rapide, mais avec précaution)\nvar parallelSum = numbers\n    .AsParallel()\n    .WithDegreeOfParallelism(Environment.ProcessorCount)\n    .Where(n => n % 2 == 0)\n    .Sum();\n\nConsole.WriteLine($"Résultat : {parallelSum}");\n
\n\n

Mais PLINQ n'est pas une panacée. Pour un traitement complexe des mégadonnées en C#, il est préférable d'utiliser Parallel.ForEach avec une gestion manuelle du partitionnement.

\n\n

Parallel.ForEach avec partitionnement par plages

\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); // votre fonction lourde\n        lock (lockObject)\n        {\n            processedCount++;\n            if (processedCount % 100_000 == 0)\n                Console.WriteLine($"Traité : {processedCount}");\n        }\n    });\n
\n\n

MemoryMappedFile : travailler avec les fichiers comme avec de la mémoire vive

\n\n

Lorsque le fichier est trop volumineux pour être chargé en RAM, mais que vous devez

Blogs

Book Recommendations