O Desafio das Um Bilhão de Linhas
Um “One Billion Row Challenge” centrado em Java para calcular min/média/max de temperaturas a partir de um arquivo de texto de 12 GB com 1 bilhão de linhas tornou-se uma vitrine para ajuste extremo de desempenho e conhecimento de sistemas. Os participantes debatem se a tarefa é limitada por I/O ou CPU, trocando técnicas como memory mapping, parsing numérico personalizado, SIMD, multi-threading e o aproveitamento do comportamento do page cache do sistema operacional, ao mesmo tempo em que discutem métodos justos de benchmark e regras que proíbem truques específicos do conjunto de dados. Muitos comparam Java otimizado manualmente com C, Rust, bancos SQL, awk e pandas, usando o exercício para explorar como hardware moderno, runtimes e ferramentas de processamento de dados se comportam sob cargas pesadas, porém conceitualmente simples.
Escopo do desafio e linguagens
- Embora seja apresentado como um desafio de Java, muitos participantes discutem e compartilham implementações em C/C++, Rust, Go, .NET, Python, Perl, Awk, R, SQL, ClickHouse, DuckDB, Pinot e outras.
- Alguns gostariam que outras linguagens da JVM fossem permitidas oficialmente, enquanto outros observam que a regra de “sem dependências externas” exclui coisas como Hadoop ou Pandas.
IO, cache e estratégias de acesso a arquivos
- Um tema central é saber se a tarefa é limitada por IO ou por CPU.
- Como o arquivo de 12 GB é executado 5 vezes em uma máquina de 32 GB e os caches não são esvaziados, as execuções posteriores efetivamente operam a partir do page cache, tornando o parsing e a agregação o principal gargalo.
- Abordagens debatidas: ler para a RAM vs
mmap, IO com buffer vsO_DIRECT,io_uring, buffers pequenos fixos e o tratamento de linhas que cruzam limites de blocos. - Alguns argumentam que depender da política de cache do sistema operacional torna o benchmark menos “puro”; outros dizem que isso reflete implantações reais.
Restrições de correção e preocupações com overfitting
- Os nomes das estações devem ser UTF-8 arbitrário (sem
;), com até 100 caracteres; as temperaturas variam de −99.9 a 99.9, com exatamente uma casa decimal. - Isso permite aritmética inteira (escala por 10) e parsing mais simples do que ponto flutuante completo.
- Várias soluções rápidas foram descobertas usando incorretamente funções de hash ou dependendo do conjunto de dados específico, e foram removidas; há debate sobre o que conta como “overfitting” injusto.
- Surgem ideias de randomização do conjunto de dados ou seeds ocultas para evitar ajustes a um único arquivo.
Debate sobre metodologia de benchmark
- O organizador descarta o mais rápido e o mais lento de 5 execuções e faz a média das 3 do meio.
- Um lado argumenta que o tempo mínimo reflete melhor o potencial algorítmico sem ruído.
- Outros respondem que médias aparadas aproximam melhor o desempenho no mundo real sob ruído do sistema, contenção de VM e efeitos de GC.
Estratégias algorítmicas e de implementação
- Sugestões comuns: processamento em streaming com agregados por estação, temperaturas inteiras, parsing numérico escrito manualmente, SIMD para busca de delimitadores e parsing, minimização de alocações e projeto cuidadoso de hash map.
- Alguns exploram ideias mais exóticas como máquinas de estado personalizadas, hashes perfeitos ou parsers especializados e stateful com SIMD, embora a viabilidade seja debatida.
Uso de bancos de dados e motores de análise
- Vários participantes demonstram motores SQL (PostgreSQL, ClickHouse, DuckDB, Pinot, kdb+/q) resolvendo a consulta de forma muito concisa, mas muitas vezes mais lentamente, especialmente incluindo ingestão.
- Há discussão sobre inchaço de armazenamento, estratégias de índices, truques com arrays, planos de consulta paralelos e COPY vs INSERT para carregamento em massa.
Java, ferramentas de build e comparações entre linguagens
- As opiniões sobre Java são mistas: alguns elogiam seu desempenho e ferramentas; outros reclamam da verbosidade e do boilerplate.
- Longas subthreads comparam Maven vs Gradle vs ferramentas de Cargo/Go, comportamento de compilação incremental e a percepção de lentidão no build.
- Alguns observam que, embora linguagens de baixo nível possam ser as mais rápidas, Java ingênuo muitas vezes supera C/C++ ingênuo por padrões mais seguros e otimizações do JIT.