Por que C# é sua ferramenta secreta para Big Data?
\n\nQuando se fala em processamento de grandes dados, logo vêm à mente Python com seu Pandas, Scala com Spark ou Java com Hadoop. Mas sejamos honestos: C# muitas vezes fica injustamente na sombra. E é uma pena. A plataforma .NET nos dá ferramentas tão poderosas como PLINQ, MemoryMappedFile, Parallel.For e fluxos assíncronos, que permitem processar gigabytes de dados em hardware comum sem complicações.
\n\nNeste artigo, não vamos divagar em teoria — vamos direto ao ponto. Você aprenderá como extrair o máximo do seu processador ao processar grandes dados em C#, como evitar o OutOfMemoryException e como processar arquivos de dezenas de gigabytes como se fossem apenas um grande livro.
\n\nO principal problema: como não matar a memória?
\n\nImagine: você tem um arquivo CSV de 50 GB com logs de servidor. Você o abre em um StreamReader comum e lê linha por linha. Tudo bem? Não. Se você tentar carregá-lo inteiro em um List<string> — olá, OutOfMemoryException. Mesmo que você tenha 64 GB de RAM, o .NET pode fragmentar a memória de tal forma que um objeto grande simplesmente não cabe no heap.
Solução número um: streaming e chunking. Não carregue tudo de uma vez — processe em pedaços.
\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\nAgora você pode processar gigabytes sem se preocupar com a memória:
\n\nawait foreach (var chunk in ReadCsvChunksAsync("logs.csv"))\n{\n ProcessChunk(chunk); // sua lógica\n}\n\n\nProcessamento paralelo: usando todos os núcleos da CPU
\n\nOk, estamos lendo dados em blocos. Mas se você tem um processador de 16 núcleos e os dados são processados sequencialmente — você está usando apenas 6% de sua capacidade. Hora de ativar a computação paralela em C#.
\n\nPLINQ — Parallel LINQ
\n\nA mágica mais simples é adicionar .AsParallel() à sua consulta LINQ. Mas com grandes dados é preciso ter cuidado: o PLINQ decide por conta própria quando paralelizar, o que pode levar a fragmentação excessiva.
var numbers = Enumerable.Range(1, 10_000_000);\n\n// LINQ comum (lento)\nvar sum = numbers.Where(n => n % 2 == 0).Sum();\n\n// PLINQ (rápido, mas com 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\nMas PLINQ não é uma panaceia. Para processamento complexo de grandes dados em C#, é melhor usar Parallel.ForEach com controle manual de divisão.
Parallel.ForEach com divisão em intervalos
\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); // sua função pesada\n lock (lockObject)\n {\n processedCount++;\n if (processedCount % 100_000 == 0)\n Console.WriteLine($"Processados: {processedCount}");\n }\n });\n\n\nMemoryMappedFile: trabalhando com arquivos como se fossem memória RAM
\n\nQuando o arquivo é grande demais para ser carregado na RAM, mas você pre