Por que Go é o novo rei do processamento de dados?
\n\nQuando se fala em processamento de grandes dados, geralmente vêm à mente Python, Spark ou Hadoop. Mas há uma linguagem que aparece cada vez mais em projetos reais da Netflix, Uber e Dropbox — é o Go. E isso não é por acaso.
\n\nImagine: você precisa processar 50 gigabytes de logs, analisar um CSV com milhões de linhas ou implantar um microsserviço para análise em tempo real. Python pode "engasgar" devido ao GIL (Global Interpreter Lock), e configurar o Spark para uma única tarefa é como usar um canhão para matar uma mosca. Go oferece o equilíbrio ideal: a velocidade de uma linguagem tipo C e a conveniência de abstrações de alto nível.
\n\nNeste artigo, vamos explorar o processamento de grandes dados em Go com exemplos reais. Você aprenderá como ler terabytes de arquivos de forma eficiente, paralelizar cálculos com goroutines e construir pipelines de dados que não "caem" sob carga. Vamos nessa!
\n\nPor que Go vence o Python em Big Data?
\n\nSejamos honestos: Python é ótimo para prototipagem. Mas quando se trata de carga de produção, Go se destaca:
\n\n- \n
- Compilação para código de máquina — sem interpretadores, inicialização instantânea. \n
- Concorrência nativa — goroutines e canais permitem processar dados em paralelo sem complicações. \n
- Baixo consumo de memória — um programa Go pode processar milhões de registros consumindo 3 a 5 vezes menos RAM que um equivalente em Python. \n
- Simplicidade de implantação — um único binário, sem dependências. \n
Claro, para processamento ML complexo, Python com Pandas e Scikit-learn continua sendo o rei. Mas para processos ETL, análise, filtragem e agregação de dados — Go é ideal.
\n\nProcessamento em streaming: lendo gigabytes sem sofrimento
\n\nA tarefa mais comum é ler um arquivo grande sem carregá-lo inteiro na memória. Em Go, isso é feito elegantemente com bufio.Scanner. Esqueça o readlines(), que consome RAM.
Exemplo: contagem de linhas em um log de 10 gigabytes
\n\npackage main\n\nimport (\n "bufio"\n "fmt"\n "log"\n "os"\n "runtime"\n)\n\nfunc main() {\n file, err := os.Open("bigdata.log")\n if err != nil {\n log.Fatal(err)\n }\n defer file.Close()\n\n scanner := bufio.NewScanner(file)\n scanner.Buffer(make([]byte, 1024*1024), 1024*1024) // buffer de 1 MB\n\n var lines int64\n for scanner.Scan() {\n lines++\n // Pode processar a linha imediatamente: scanner.Text()\n }\n\n if err := scanner.Err(); err != nil {\n log.Fatal(err)\n }\n\n fmt.Printf("Total de linhas: %d\\n", lines)\n fmt.Printf("Consumo de memória: %.2f MB\\n", float64(runtime.ReadMemStats(&runtime.MemStats{}).Alloc)/1024/1024)\n}\n\nEste código não carrega o arquivo na memória. Ele o lê em pedaços (buffer de 1 MB), processando linha por linha. Ideal para processamento de grandes dados em Go.
\n\nProcessamento paralelo: goroutines em ação
\n\nUm núcleo é bom, mas quatro são melhores. Go permite paralelizar facilmente o processamento de dados. Vamos criar um pipeline de dados: ler linhas, processá-las em várias threads e coletar o resultado.
\n\nExemplo: filtragem de endereços IP de um log
\n\npackage main\n\nimport (\n "bufio"\n "fmt"\n "log"\n "os"\n "regexp"\n "sync"\n)\n\nfunc main() {\n file, err := os.Open("access.log")\n if err != nil {\n log.Fatal(err)\n }\n defer file.Close()\n\n scanner := bufio.NewScanner(file)\n lines := make(chan string, 100) // canal bufferizado\n\n // Workers para processamento\n var wg sync.WaitGroup\n ipPattern := regexp.MustCompile(`\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}`)\n results := make(chan string, 100)\n\n // Iniciar 4 workers\n for i := 0; i <