O Desafio de Um Bilhão de Linhas em Go: de 1m45s a 4s em nove soluções

Otimizar código Go para o “1 Billion Row Challenge” — processar um arquivo de texto de 13 GB com 1 bilhão de linhas de medições de temperatura — mostra até onde um programa simples pode ir com profiling cuidadoso, estruturas de dados personalizadas e paralelismo, indo de quase dois minutos até cerca de quatro segundos. Os comentários comparam esses resultados em Go com abordagens altamente afinadas em Java, .NET, C++, Rust e até soluções baseadas em bancos de dados e GPUs, observando que toolchains JIT/AOT de JVM e .NET, além de suporte a SIMD, podem alcançar tempos ainda menores ao custo de código extremo e pouco idiomático. Muitos enfatizam que, embora esses micro-benchmarks sejam uma forma divertida de explorar limites de desempenho, soluções do mundo real precisam equilibrar velocidade bruta com simplicidade, robustez, portabilidade e as capacidades de bibliotecas e bancos de dados de mais alto nível.

Comparações de desempenho entre linguagens

  • A discussão gira em torno de por que as soluções mais rápidas em Java e C#/.NET superam as mais rápidas em Go, às vezes por fatores de 2 a 4x.
  • Alguns argumentam que Java e .NET se beneficiam de JIT/AOT muito agressivo, intrínsecos SIMD, PGO e décadas de otimização de runtime.
  • Outros contrapõem que o Go pode, em princípio, usar truques algorítmicos semelhantes; a lacuna está mais no esforço de implementação do que em uma impossibilidade inerente.
  • Há debate sobre afirmações de que a JVM pode “frequentemente superar C”; céticos argumentam que isso só é verdade em casos selecionados.
  • Rust, C++, Swift, Dart, Node.js e até R são mencionados por meio de outros leaderboards ou exemplos, mas as comparações ficam confusas por causa de hardware diferente.

Técnicas de otimização e estruturas de dados

  • Truques-chave: tabelas de hash personalizadas, IO mapeada em memória, parsing de temperatura apenas com inteiros, desenrolamento de loops e uso cuidadoso de acesso inseguro à memória.
  • Discussão sobre possíveis ganhos adicionais: arrays alocados na stack, redução de copy(), tries antecipadas para nomes de estações, tabelas de consulta para temperaturas e hashing perfeito.
  • Vários participantes duvidam que LUTs grandes superem a aritmética simples devido a custos de cache e latência de memória.

IO, cache e ressalvas de benchmark

  • Muitos observam que execuções repetidas mantêm o arquivo de 13 GB no cache do SO ou em disco RAM, então a largura de banda do disco não é o gargalo.
  • Perguntas sobre soluções em Java aparentemente excedendo a taxa de transferência de SSD são respondidas com explicações sobre cache e sistemas de arquivos em RAM.
  • Alguns observam que o paralelismo traz grandes ganhos, mas não é diretamente comparável a ferramentas monothread como cat.

Bibliotecas, bancos de dados, GPUs e ferramentas de alto nível

  • Pessoas testam ou propõem Polars, DuckDB, BigQuery, bancos SQL e até GPUs; essas abordagens podem chegar a dezenas de segundos ou alguns minutos com código bem mais alto nível.
  • Alguns argumentam que, em sistemas reais, fazer mais trabalho dentro de bancos de dados pode ser competitivo e operacionalmente mais simples do que código feito na mão.

Relevância no mundo real e notas específicas de Go

  • Vários enfatizam que o exercício é um “jogo”: código real precisaria de parsing robusto e tratamento de erros, trocando velocidade por correção.
  • Outros focam nas limitações do compilador de Go (história fraca com SIMD, PGO modesto, inlining menos agressivo) em comparação com toolchains Java/.NET mais maduros, ao mesmo tempo em que destacam os pontos fortes do Go em simplicidade e inicialização rápida.
  • O profiling com pprof do Go e técnicas como desabilitar o GC, bloquear threads do SO e usar ponteiros inseguros são destacados como úteis, mas pouco idiomáticos.