All Benchmarks

Go Benchmark

Random Number Generation

math/rand vs math/rand/v2 vs crypto/rand for "I just need a random int".

randrandommath-randcrypto-randrand-v2stdlib

Every Go developer eventually types "random int" into a search engine and gets three answers: the legacy math/rand, its Go 1.22 successor math/rand/v2, and crypto/rand. This benchmark draws a small random integer with each package. math/rand/v2 replaces the v1 global generator (and its lock contention) with a faster ChaCha8-based per-thread design, while crypto/rand pays for cryptographic security on every draw. The rule of thumb the chart confirms: use math/rand/v2 for everything non-security (v1 is effectively deprecated), and reserve crypto/rand for keys, tokens, and anything an attacker must not predict.

linux/amd64AMD Ryzen 9 9950X3D 16-Core Processorbenchmarks/rand-v1-vs-v2
Compare atCPUs

1 CPU

Fastest

Math Rand V2

4.7 ns/op

Slowest

Crypto Rand

215.37 ns/op · 46x slower

32 CPUs

Fastest

Math Rand V2

4.58 ns/op

Slowest

Crypto Rand

216.79 ns/op · 47x slower

Performance Comparison (lower is better)
CPU:
#1

Math Rand V2 #

Fastest

rand.IntN(100) from math/rand/v2 (Go 1.22+). The global functions use a ChaCha8-based generator with cheap per-thread state instead of a global lock, and the range reduction algorithm avoids v1's modulo bias trick. Faster, safer seeding by default, and the idiomatic choice for all non-cryptographic randomness.

CPU Scaling (lower is better)
// randRange is the exclusive upper bound for the generated random numbers.
const randRange = 100

func BenchmarkMathRandV2_run(b *testing.B) {
	for i := 0; i < b.N; i++ {
		sink = rand.IntN(randRange)
	}
}
1 CPU
45.9xfaster(4486%)thanCrypto Rand
1.5xfaster(46%)thanMath Rand
32 CPUs
47.3xfaster(4631%)thanCrypto Rand
1.5xfaster(49%)thanMath Rand
#2

Math Rand #

rand.Intn(100) from the legacy math/rand. The global functions share one generator behind a mutex, so concurrent use contends, and the underlying algorithm is a decades-old additive generator. Kept around for compatibility; new code should not use it.

CPU Scaling (lower is better)
// randRange is the exclusive upper bound for the generated random numbers.
const randRange = 100

func BenchmarkMathRand_run(b *testing.B) {
	for i := 0; i < b.N; i++ {
		sink = rand.Intn(randRange)
	}
}
1 CPU
31.5xfaster(3048%)thanCrypto Rand
1.5xslower(46%)thanMath Rand V2
32 CPUs
31.7xfaster(3065%)thanCrypto Rand
1.5xslower(49%)thanMath Rand V2
#3

Crypto Rand #

Slowest

rand.Int(rand.Reader, max) from crypto/rand, which reads from the operating system's CSPRNG and allocates big.Int values along the way. Orders of magnitude slower — and completely worth it whenever the random value is security-relevant: session tokens, keys, nonces, password salts.

CPU Scaling (lower is better)
// randRange is the exclusive upper bound for the generated random numbers.
const randRange = 100

func BenchmarkCryptoRand_run(b *testing.B) {
	upperBound := big.NewInt(randRange)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		n, _ := rand.Int(rand.Reader, upperBound)
		sink = int(n.Int64())
	}
}
1 CPU
31.5xslower(3048%)thanMath Rand
45.9xslower(4486%)thanMath Rand V2
32 CPUs
31.7xslower(3065%)thanMath Rand
47.3xslower(4631%)thanMath Rand V2

Contributors