¿Por qué C# es su herramienta secreta para Big Data?
\n\nCuando se habla de procesamiento de grandes datos, lo primero que viene a la mente son Python con sus Pandas, Scala con Spark o Java con Hadoop. Pero seamos honestos: C# a menudo queda injustamente en la sombra. Y es una lástima. La plataforma .NET nos brinda herramientas tan potentes como PLINQ, MemoryMappedFile, Parallel.For y flujos asíncronos, que permiten procesar gigabytes de datos en hardware común sin complicaciones.
\n\nEn este artículo no divagaremos con teoría — pasaremos directamente a la acción. Aprenderá cómo sacar el máximo provecho de su procesador al procesar grandes datos en C#, cómo evitar caer en OutOfMemoryException y cómo manejar archivos de decenas de gigabytes como si fueran un libro grande.
\n\nEl problema principal: ¿cómo no matar la memoria?
\n\nImagine: tiene un archivo CSV de 50 GB con registros del servidor. Lo abre con un StreamReader normal y lo lee línea por línea. ¿Todo bien? No. Si intenta cargarlo completamente en un List<string> — hola, OutOfMemoryException. Incluso si tiene 64 GB de RAM, .NET puede fragmentar la memoria de tal manera que un objeto grande simplemente no quepa en el montón.
Solución número uno: streaming y fragmentación en chunks. No cargue todo de una vez — mastique por partes.
\n\npublic 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\nAhora puede procesar gigabytes sin preocuparse por la memoria:
\n\nawait foreach (var chunk in ReadCsvChunksAsync("logs.csv"))\n{\n ProcessChunk(chunk); // su lógica\n}\n\n\nProcesamiento paralelo: usando todos los núcleos del procesador
\n\nBien, leemos datos en porciones. Pero si tiene un procesador de 16 núcleos y los datos se procesan secuencialmente — está usando solo el 6% de su capacidad. Es hora de activar la computación paralela en C#.
\n\nPLINQ — Parallel LINQ
\n\nLa magia más simple es agregar .AsParallel() a su consulta LINQ. Pero con grandes datos hay que tener cuidado: PLINQ decide por sí mismo cuándo paralelizar, y esto puede provocar una fragmentación excesiva.
var numbers = Enumerable.Range(1, 10_000_000);\n\n// LINQ normal (lento)\nvar sum = numbers.Where(n => n % 2 == 0).Sum();\n\n// PLINQ (rápido, pero con cuidado)\nvar parallelSum = numbers\n .AsParallel()\n .WithDegreeOfParallelism(Environment.ProcessorCount)\n .Where(n => n % 2 == 0)\n .Sum();\n\nConsole.WriteLine($"Resultado: {parallelSum}");\n\n\nPero PLINQ no es una panacea. Para el procesamiento complejo de grandes datos en C#, es mejor usar Parallel.ForEach con control manual de la división.
Parallel.ForEach con división en rangos
\n\nvar 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); // su función pesada\n lock (lockObject)\n {\n processedCount++;\n if (processedCount % 100_000 == 0)\n Console.WriteLine($"Procesados: {processedCount}");\n }\n });\n\n\nMemoryMappedFile: trabajando con archivos como si fueran memoria RAM
\n\nCuando el archivo es demasiado grande para cargarlo en RAM, pero necesita