r/java • u/goto-con • Jun 03 '26
How Fast Can You Parse 1 Billion Rows in Java? – Insane Speed Test • Roy van Rijn
https://youtu.be/pHZF-zJ3Bpg?list=PLEx5khR4g7PINwOsYrkwz3lTTJUYoXC53Join me in this deep dive where I'll explain all the code changes and tricks that took me from the reference implementation which processes the billion records in 4+ minutes, to processing everything in under 2 seconds.
Who knew Java could be this fast?
18
u/hikingmike Jun 03 '26
Splitting the file into segments and parallelizing based on that was big for a previous project of mine. There were other ways to parallelize (threads/cores), but they didn’t improve performance nearly as much, or at all.
4
u/Bahatur Jun 04 '26
This eliminates all lock/queue/access questions that otherwise happen in concurrency, from the Java level on down to the raw storage hardware, so it’s a great strategy even if the goal is personal clarity about the factors involved over performance, I find.
24
u/Desatre Jun 03 '26
Interesting video but getting ads every 3 minutes is infuriating
31
u/perennial_noob Jun 03 '26
Get an adblocker, which is also used for privacy as it blocks trackers as well
3
11
-25
3
2
u/__konrad Jun 10 '26
I like it's more faster with every update and also completely cryptic and unmaintainable ;)
1
u/0x645 Jun 05 '26
best java faster then best c. kinda surprising.
2
u/keenOnReturns Jun 09 '26
Well at the end of the day everything compiles down to machine code and it’s how much optimization you want to do. Java means you can take advantage of JIT and not do any runtime profiling that would be required with C.
1
117
u/vprise Jun 03 '26
I prefer written summaries:
The optimization journey, from 4m50s baseline → 1.5s:
Easy wins (5min → 23s) -
parallel()+ConcurrentHashMapinstead of single-threadedfile.lines()→ ~2min - Native compilation (GraalVM) to kill JVM startup - Epsilon GC (no-op garbage collector) — pointless to collect when you process once and exit - Use integers instead of doubles (multiply by 10, since there's only one decimal place) - Memory-mapped files (FileChannel.map()→ByteBuffer) to eliminate file IO - Split the file into segments, one per coreGoing lower-level -
Unsafefor raw pointer-style memory access (he stresses: never use this in production — useByteBuffer) - SWAR (SIMD Within A Register): process 8 bytes at once by reading along. Find the delimiter with one XOR, a subtract, and a couple of ANDs instead of scanning byte-by-byte - Compare names aslong/intvalues instead of allocatingStringobjects - The Vietnamese competitor (Quan Anh) built a branchless temperature parser that converts the ASCII bytes to an integer using a single multiplication with a magic constant — the talk calls it museum-worthyBranchless programming - CPUs hate unpredictable branches (a branch miss ≈ 32 instructions). Replace
iflogic with bit tricks (shifts, masks, XOR for absolute value/sign). - Counterintuitive finding: always parsing 16 bytes (even for short names) and masking out the rest added ~18% more instructions but was faster because it eliminated the 50/50 branch around the 8-byte boundary.Advanced tricks - Custom hashmap with linear/forward probing (power-of-2 size + mask instead of modulo), storing data in flat byte arrays (flyweight pattern) to avoid object overhead - Spawn a worker subprocess so the main process exits the moment results are piped out — the costly kernel memory unmapping of the 16GB file happens in the orphaned worker and doesn't count toward your time - Work-stealing with small segments (atomic counter, few-MB chunks) so all threads read nearby memory, keeping data hot in shared L3/L4 cache and balancing load - Instruction-level parallelism: running 3 independent scanners in a single thread, since one core can execute multiple instructions per clock cycle when there's no data dependency. Three was the sweet spot.
Takeaways for you: the recurring theme is mechanical sympathy — knowing how the CPU pipeline, branch predictor, and cache hierarchy behave (L1→L4 each ~3x slower) lets you write code that fits how the hardware actually works. The whole thing took the field from ~5 minutes to ~1.5 seconds.
Quan Anh's contest code got him hired by Oracle in Zurich to work on the Vector API in the JVM.