Go's regex engine (RE2) prioritizes safety by preventing catastrophic backtracking through linear-time guarantees, but this design choice results in 3-78x slower performance compared to Rust's regex crate, which achieves the same safety guarantees while being 67-78x faster through lazy DFA construction, SIMD vectorization, and pre-filtering techniques.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
Go's regex is 78x slower than Rust's. Google did it on purpose.
Added:I benchmarked Go's regex engine against Rust. Same patterns, same 200 megabytes of logs, and the match counts came out identical every single time. The worst [music] case, 78 times slower. And here's the twist that makes this worth 10 minutes of your life. Go is slow on purpose. [music] To see why, you first need to watch a regex commit murder.
This is a ReDoS, a regular expression denial of service.
>> [music] >> The pattern looks harmless. One or more A's wrapped in a group that also repeats, then end of line. I hand Python a string of 30 A's and one exclamation mark. And it's gone. At 28 characters, this takes 10 seconds, and every character you add doubles it. 40 characters would run for 11 hours. 64, 21,000 years. Now, the same pattern in Go on 100,000 characters, 4 milliseconds. That's not luck. That's a guarantee.
Here's what's eating Python alive. A backtracking engine tries possibilities.
That nested quantifier means every single A can belong to the inner loop or start a new pass of the outer one. So, the tree of ways to split the string doubles with each character. When the match finally dies at the exclamation mark, the engine crawls back and tries every other split. 28 characters in, that's over a quarter of a billion paths. This [music] is the explosion.
Google's answer was RE2, and it's what Go ships as the standard library. It never backtracks because it is never trying paths in the first place. The pattern becomes a state machine, and that [music] machine gets dragged across your input exactly once, one step per byte, no matter how evil the pattern is.
Worst case equals best case. Go looked at a 40-year-old foot gun and simply deleted it. Genuinely, respect.
So, that's the defense, and it's a good one. But, somewhere along the way, we chose safety became the permanent excuse for something else, because that same one-pass design exists in Rust with the same guarantee and the same immunity to the explosion you just watched. So, let's race them. Honestly, same file, same patterns, and the output has to match to the last digit.
The entire Rust program, take a pattern from the command line, read 200 megabytes of logs into one string, compile the regex, count every match, print [music] the count. A dozen lines, nothing clever, no unsafe, no tricks.
The regex crate does all the work.
And Go. The same job, almost character for character. Read the file, compile the pattern, count the matches.
Honestly, the Go version is the nicer one to type. Both programs print their match count, and across every test in this video, those counts agreed exactly.
Same work, same answers. Now, the clock.
[music] First, real pattern. Find every email address in the logs. Rust, [music] done.
A fifth of a second, and most of that was just reading the file off disk.
225,694 matches. Now, Go. Same regex, same file.
And now, we wait. The cursor isn't stuck. This is the design working exactly as intended. 7 seconds. And there it is, the identical match count to the digit. The answers match. The bills [music] don't.
Under hyper fine, warmed up, and averaged over runs, it stops being a feeling and becomes a number. Rust, 102 milliseconds. Go, 6.8 seconds. 67 times.
Look at the left panel. In the time Go needs to scan the file once, Rust has already rerun the entire job 66 more times.
>> [music] >> And it's not one cherry-picked regex. A plain literal string, three times faster. A bounded repeat, the shape of every access key scanner, 11 times. The email pattern, 67. And a case-insensitive alternation, the bread and butter of every log search ever written, 78 times faster. Same guarantee on every row, identical counts on every row. The gap grows exactly where regexes get useful.
>> [music] >> Let's make it hurt. 1 GB of logs, five error keywords, case-insensitive. Rust, 2.3 seconds. Done before you've settled into your chair. Go's [music] turn. And I'm going to fast forward here because nobody has time for the raw footage. A minute, 31.7 seconds for the identical 938,000 matches. [music] If this scan runs hourly in your pipeline, that gap is not a benchmark anymore. It's your compute bill.
>> [music] >> So, how is the same guaranteed this much faster?
Two reasons, both pure engineering. Rust builds the state machine lazily and caches it. So, the hot loop is a tight DFA sprint. And before that loop even runs, Cindy pre-filters chew through memory 16 bytes per instruction, skipping straight to the only places a match could possibly start. Go walks its automata on one byte at a time, and Go's compiler will not vectorize that walk.
Same idea on paper, wildly different execution.
And before you ask if Rust paid for this with safety, the exact pattern that hung Python on 100,000 characters in Rust under 100 nanoseconds. The guarantee survived the speed.
Full credit where it's due. Go shipped regex safety as the default when almost nobody else would, and its engine still compiles patterns fast, [music] which matters when you build regexes on the fly. But, Rust's regex crate has carried the exact same linear time guarantee for about a decade, while being one to orders of magnitude faster at actually matching. Safety was the reason. At some point, it quietly became the excuse.
So, here's my actual take.
Using Go's [music] regex B is completely fine right up until the input grows six zeros. If you grep logs, scan requests, or filter events at real volume, then safe but 78 times slower is a decision someone made for you in 2012, and you're still paying the invoice.
Rust made the other decision, keep the guarantee, then spend 10 years making it fly. Safety versus speed was never the trade-off.
It was the excuse.
Every number in this video came off my laptop. The programs, the logs, and the measurements are real, and the match counts agreed on every single run. If you want more experiments where the receipts actually exist, subscribe.
[music] I run these so you don't have to.
Related Videos

TOP 15 Data compression Interview Questions and Answers 2019 Part-2 | Data compression | Wisdom jobs
wisdomjobs
281 views•2019-06-28

CTS 158: 802.11w Management Frame Protection
ClearToSend
4K views•2019-02-04

NDSS 2019 Send Hardest Problems My Way: Probabilistic Path Prioritization for Hybrid Fuzzing
NDSSSymposium
496 views•2019-04-02

How realistic is Cities: Skylines?
CityBeautiful
159K views•2019-02-14

GUIs & TUIs: Choosing a User Interface for Your Python Project | Real Python Podcast
realpython
2K views•2025-04-04

The OSI Model - Explained by Example
hnasr
225K views•2019-05-12

Cloud Computing - Introduction
elithecomputerguy
98K views•2019-10-07

From Traveler's Dilemma to Dynamic Routing | Demystifying Networking
IITBombayJuly
5K views•2019-08-04
Trending

Playstation NO DISC/NO BUY Fight Is Over...
DavidJaffeGames
4K views•2026-07-23

Steam and Xbox Just Dropped The Hammer On PlayStation
OhNoItsAlexx
9K views•2026-07-23

Americans Confused in Australia for 17 Minutes Straight
IWrocker
17K views•2026-07-23

SuperBike Factory Has Gone... What's Next for the Motorcycle Industry?
thatbikersimon
11K views•2026-07-22