Repository: valyala/fastrand
Branch: master
Commit: 679a6fad9d7a
Files: 7
Total size: 9.8 KB
Directory structure:
gitextract_9pfnkqbg/
├── .travis.yml
├── LICENSE
├── README.md
├── fastrand.go
├── fastrand_test.go
├── fastrand_timing_test.go
└── go.mod
================================================
FILE CONTENTS
================================================
================================================
FILE: .travis.yml
================================================
language: go
go:
- 1.7
- 1.8
script:
# build test for supported platforms
- GOOS=linux go build
- GOOS=darwin go build
- GOOS=freebsd go build
- GOARCH=386 go build
# run tests on a standard platform
- go test -v ./...
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2017 Aliaksandr Valialkin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
[](https://travis-ci.org/valyala/fastrand)
[](http://godoc.org/github.com/valyala/fastrand)
[](https://goreportcard.com/report/github.com/valyala/fastrand)
# fastrand
Fast pseudorandom number generator.
# Features
- Optimized for speed.
- Performance scales on multiple CPUs.
# How does it work?
It abuses [sync.Pool](https://golang.org/pkg/sync/#Pool) for maintaining
"per-CPU" pseudorandom number generators.
TODO: firgure out how to use real per-CPU pseudorandom number generators.
# Benchmark results
```
$ GOMAXPROCS=1 go test -bench=. github.com/valyala/fastrand
goos: linux
goarch: amd64
pkg: github.com/valyala/fastrand
BenchmarkUint32n 50000000 29.7 ns/op
BenchmarkRNGUint32n 200000000 6.50 ns/op
BenchmarkRNGUint32nWithLock 100000000 21.5 ns/op
BenchmarkMathRandInt31n 50000000 31.8 ns/op
BenchmarkMathRandRNGInt31n 100000000 17.9 ns/op
BenchmarkMathRandRNGInt31nWithLock 50000000 30.2 ns/op
PASS
ok github.com/valyala/fastrand 10.634s
```
```
$ GOMAXPROCS=2 go test -bench=. github.com/valyala/fastrand
goos: linux
goarch: amd64
pkg: github.com/valyala/fastrand
BenchmarkUint32n-2 100000000 17.6 ns/op
BenchmarkRNGUint32n-2 500000000 3.36 ns/op
BenchmarkRNGUint32nWithLock-2 50000000 32.0 ns/op
BenchmarkMathRandInt31n-2 20000000 51.2 ns/op
BenchmarkMathRandRNGInt31n-2 100000000 11.0 ns/op
BenchmarkMathRandRNGInt31nWithLock-2 20000000 91.0 ns/op
PASS
ok github.com/valyala/fastrand 9.543s
```
```
$ GOMAXPROCS=4 go test -bench=. github.com/valyala/fastrand
goos: linux
goarch: amd64
pkg: github.com/valyala/fastrand
BenchmarkUint32n-4 100000000 14.2 ns/op
BenchmarkRNGUint32n-4 500000000 3.30 ns/op
BenchmarkRNGUint32nWithLock-4 20000000 88.7 ns/op
BenchmarkMathRandInt31n-4 10000000 145 ns/op
BenchmarkMathRandRNGInt31n-4 200000000 8.35 ns/op
BenchmarkMathRandRNGInt31nWithLock-4 20000000 102 ns/op
PASS
ok github.com/valyala/fastrand 11.534s
```
As you can see, [fastrand.Uint32n](https://godoc.org/github.com/valyala/fastrand#Uint32n)
scales on multiple CPUs, while [rand.Int31n](https://golang.org/pkg/math/rand/#Int31n)
doesn't scale. Their performance is comparable on `GOMAXPROCS=1`,
but `fastrand.Uint32n` runs 3x faster than `rand.Int31n` on `GOMAXPROCS=2`
and 10x faster than `rand.Int31n` on `GOMAXPROCS=4`.
================================================
FILE: fastrand.go
================================================
// Package fastrand implements fast pesudorandom number generator
// that should scale well on multi-CPU systems.
//
// Use crypto/rand instead of this package for generating
// cryptographically secure random numbers.
package fastrand
import (
"sync"
"time"
)
// Uint32 returns pseudorandom uint32.
//
// It is safe calling this function from concurrent goroutines.
func Uint32() uint32 {
v := rngPool.Get()
if v == nil {
v = &RNG{}
}
r := v.(*RNG)
x := r.Uint32()
rngPool.Put(r)
return x
}
var rngPool sync.Pool
// Uint32n returns pseudorandom uint32 in the range [0..maxN).
//
// It is safe calling this function from concurrent goroutines.
func Uint32n(maxN uint32) uint32 {
x := Uint32()
// See http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
return uint32((uint64(x) * uint64(maxN)) >> 32)
}
// RNG is a pseudorandom number generator.
//
// It is unsafe to call RNG methods from concurrent goroutines.
type RNG struct {
x uint32
}
// Uint32 returns pseudorandom uint32.
//
// It is unsafe to call this method from concurrent goroutines.
func (r *RNG) Uint32() uint32 {
for r.x == 0 {
r.x = getRandomUint32()
}
// See https://en.wikipedia.org/wiki/Xorshift
x := r.x
x ^= x << 13
x ^= x >> 17
x ^= x << 5
r.x = x
return x
}
// Uint32n returns pseudorandom uint32 in the range [0..maxN).
//
// It is unsafe to call this method from concurrent goroutines.
func (r *RNG) Uint32n(maxN uint32) uint32 {
x := r.Uint32()
// See http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
return uint32((uint64(x) * uint64(maxN)) >> 32)
}
// Seed sets the r state to n.
func (r *RNG) Seed(n uint32) {
r.x = n
}
func getRandomUint32() uint32 {
x := time.Now().UnixNano()
return uint32((x >> 32) ^ x)
}
================================================
FILE: fastrand_test.go
================================================
package fastrand
import (
"testing"
)
func TestRNGSeed(t *testing.T) {
var r RNG
for _, seed := range []uint32{1, 2, 1234, 432432, 34324432} {
r.Seed(seed)
m := make(map[uint32]struct{})
for i := 0; i < 1e6; i++ {
n := r.Uint32()
if _, ok := m[n]; ok {
t.Fatalf("number %v already exists", n)
}
m[n] = struct{}{}
}
}
}
func TestUint32(t *testing.T) {
m := make(map[uint32]struct{})
for i := 0; i < 1e6; i++ {
n := Uint32()
if _, ok := m[n]; ok {
t.Fatalf("number %v already exists", n)
}
m[n] = struct{}{}
}
}
func TestRNGUint32(t *testing.T) {
var r RNG
m := make(map[uint32]struct{})
for i := 0; i < 1e6; i++ {
n := r.Uint32()
if _, ok := m[n]; ok {
t.Fatalf("number %v already exists", n)
}
m[n] = struct{}{}
}
}
func TestUint32n(t *testing.T) {
m := make(map[uint32]int)
for i := 0; i < 1e6; i++ {
n := Uint32n(1e2)
if n >= 1e2 {
t.Fatalf("n > 1000: %v", n)
}
m[n]++
}
// check distribution
avg := 1e6 / 1e2
for k, v := range m {
p := (float64(v) - float64(avg)) / float64(avg)
if p < 0 {
p = -p
}
if p > 0.05 {
t.Fatalf("skew more than 5%% for k=%v: %v", k, p*100)
}
}
}
func TestRNGUint32n(t *testing.T) {
var r RNG
m := make(map[uint32]int)
for i := 0; i < 1e6; i++ {
n := r.Uint32n(1e2)
if n >= 1e2 {
t.Fatalf("n > 1000: %v", n)
}
m[n]++
}
// check distribution
avg := 1e6 / 1e2
for k, v := range m {
p := (float64(v) - float64(avg)) / float64(avg)
if p < 0 {
p = -p
}
if p > 0.05 {
t.Fatalf("skew more than 5%% for k=%v: %v", k, p*100)
}
}
}
================================================
FILE: fastrand_timing_test.go
================================================
package fastrand
import (
"math/rand"
"sync"
"sync/atomic"
"testing"
"unsafe"
)
// BenchSink prevents the compiler from optimizing away benchmark loops.
var BenchSink uint32
func BenchmarkUint32n(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
s := uint32(0)
for pb.Next() {
s += Uint32n(1e6)
}
atomic.AddUint32(&BenchSink, s)
})
}
func BenchmarkRNGUint32n(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
var r RNG
s := uint32(0)
for pb.Next() {
s += r.Uint32n(1e6)
}
atomic.AddUint32(&BenchSink, s)
})
}
func BenchmarkRNGUint32nWithLock(b *testing.B) {
var r RNG
var rMu sync.Mutex
b.RunParallel(func(pb *testing.PB) {
s := uint32(0)
for pb.Next() {
rMu.Lock()
s += r.Uint32n(1e6)
rMu.Unlock()
}
atomic.AddUint32(&BenchSink, s)
})
}
func BenchmarkRNGUint32nArray(b *testing.B) {
var rr [64]struct {
r RNG
mu sync.Mutex
// pad prevents from false sharing
pad [64 - (unsafe.Sizeof(RNG{})+unsafe.Sizeof(sync.Mutex{}))%64]byte
}
var n uint32
b.RunParallel(func(pb *testing.PB) {
s := uint32(0)
for pb.Next() {
idx := atomic.AddUint32(&n, 1)
r := &rr[idx%uint32(len(rr))]
r.mu.Lock()
s += r.r.Uint32n(1e6)
r.mu.Unlock()
}
atomic.AddUint32(&BenchSink, s)
})
}
func BenchmarkMathRandInt31n(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
s := uint32(0)
for pb.Next() {
s += uint32(rand.Int31n(1e6))
}
atomic.AddUint32(&BenchSink, s)
})
}
func BenchmarkMathRandRNGInt31n(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
r := rand.New(rand.NewSource(42))
s := uint32(0)
for pb.Next() {
s += uint32(r.Int31n(1e6))
}
atomic.AddUint32(&BenchSink, s)
})
}
func BenchmarkMathRandRNGInt31nWithLock(b *testing.B) {
r := rand.New(rand.NewSource(42))
var rMu sync.Mutex
b.RunParallel(func(pb *testing.PB) {
s := uint32(0)
for pb.Next() {
rMu.Lock()
s += uint32(r.Int31n(1e6))
rMu.Unlock()
}
atomic.AddUint32(&BenchSink, s)
})
}
func BenchmarkMathRandRNGInt31nArray(b *testing.B) {
var rr [64]struct {
r *rand.Rand
mu sync.Mutex
// pad prevents from false sharing
pad [64 - (unsafe.Sizeof(RNG{})+unsafe.Sizeof(sync.Mutex{}))%64]byte
}
for i := range rr {
rr[i].r = rand.New(rand.NewSource(int64(i)))
}
var n uint32
b.RunParallel(func(pb *testing.PB) {
s := uint32(0)
for pb.Next() {
idx := atomic.AddUint32(&n, 1)
r := &rr[idx%uint32(len(rr))]
r.mu.Lock()
s += uint32(r.r.Int31n(1e6))
r.mu.Unlock()
}
atomic.AddUint32(&BenchSink, s)
})
}
================================================
FILE: go.mod
================================================
module github.com/valyala/fastrand
gitextract_9pfnkqbg/ ├── .travis.yml ├── LICENSE ├── README.md ├── fastrand.go ├── fastrand_test.go ├── fastrand_timing_test.go └── go.mod
SYMBOL INDEX (20 symbols across 3 files)
FILE: fastrand.go
function Uint32 (line 16) | func Uint32() uint32 {
function Uint32n (line 32) | func Uint32n(maxN uint32) uint32 {
type RNG (line 41) | type RNG struct
method Uint32 (line 48) | func (r *RNG) Uint32() uint32 {
method Uint32n (line 65) | func (r *RNG) Uint32n(maxN uint32) uint32 {
method Seed (line 72) | func (r *RNG) Seed(n uint32) {
function getRandomUint32 (line 76) | func getRandomUint32() uint32 {
FILE: fastrand_test.go
function TestRNGSeed (line 7) | func TestRNGSeed(t *testing.T) {
function TestUint32 (line 22) | func TestUint32(t *testing.T) {
function TestRNGUint32 (line 33) | func TestRNGUint32(t *testing.T) {
function TestUint32n (line 45) | func TestUint32n(t *testing.T) {
function TestRNGUint32n (line 68) | func TestRNGUint32n(t *testing.T) {
FILE: fastrand_timing_test.go
function BenchmarkUint32n (line 14) | func BenchmarkUint32n(b *testing.B) {
function BenchmarkRNGUint32n (line 24) | func BenchmarkRNGUint32n(b *testing.B) {
function BenchmarkRNGUint32nWithLock (line 35) | func BenchmarkRNGUint32nWithLock(b *testing.B) {
function BenchmarkRNGUint32nArray (line 49) | func BenchmarkRNGUint32nArray(b *testing.B) {
function BenchmarkMathRandInt31n (line 71) | func BenchmarkMathRandInt31n(b *testing.B) {
function BenchmarkMathRandRNGInt31n (line 81) | func BenchmarkMathRandRNGInt31n(b *testing.B) {
function BenchmarkMathRandRNGInt31nWithLock (line 92) | func BenchmarkMathRandRNGInt31nWithLock(b *testing.B) {
function BenchmarkMathRandRNGInt31nArray (line 106) | func BenchmarkMathRandRNGInt31nArray(b *testing.B) {
Condensed preview — 7 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (11K chars).
[
{
"path": ".travis.yml",
"chars": 241,
"preview": "language: go\n\ngo:\n - 1.7\n - 1.8\n\nscript:\n # build test for supported platforms\n - GOOS=linux go build\n - GOOS=darwi"
},
{
"path": "LICENSE",
"chars": 1087,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2017 Aliaksandr Valialkin\n\nPermission is hereby granted, free of charge, to any per"
},
{
"path": "README.md",
"chars": 2816,
"preview": "[](https://travis-ci.org/valyala/fastrand)\n[\n\nfunc TestRNGSeed(t *testing.T) {\n\tvar r RNG\n\tfor _, seed := range []uint32{1, 2"
},
{
"path": "fastrand_timing_test.go",
"chars": 2533,
"preview": "package fastrand\n\nimport (\n\t\"math/rand\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"unsafe\"\n)\n\n// BenchSink prevents the compile"
},
{
"path": "go.mod",
"chars": 35,
"preview": "module github.com/valyala/fastrand\n"
}
]
About this extraction
This page contains the full source code of the valyala/fastrand GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 7 files (9.8 KB), approximately 3.5k tokens, and a symbol index with 20 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.