Which way is faster in Go?

Every benchmark on this site takes one task, implements it several ways, and measures them with go test -bench on the same machine. The results are rendered as interactive charts, so you can see not just which approach wins, but how each one scales with input size and CPU count.

24
benchmarks
79
implementations
1–32
CPU cores

All benchmarks

24 comparisons of common Go patterns, from string handling to concurrency.

Request a benchmark
Array vs Slice
Compare fixed-size arrays, pre-allocated slices, and dynamically grown slices.
arraysliceallocation
3 implementationsup to 8.9x difference
Channel vs Mutex
Sharing a value by communicating vs communicating by sharing.
channelmutexsyncconcurrency+1
2 implementationsup to 1.7x difference
Concurrent Map Access
Compare sync.Map against a RWMutex-protected map for concurrent reads and writes.
mapconcurrencysync
2 implementationsup to 1.6x difference
Counter
Compare plain int, atomic, and mutex-based counters for increments and reads.
counteratomicmutexconcurrency
4 implementationsup to 37x difference
Error Handling Cost
What creating, wrapping, and inspecting errors really costs.
errorserror-wrappingerrors-iserrors-as+2
6 implementationsup to 84x difference
Int to String
Compare integer-to-string conversion methods in Go's standard library.
formattingconversionstringint+1
4 implementationsup to 3.0x difference
Interface vs Direct Method Call
Measure the overhead of calling a method through an interface instead of on the concrete type.
interfacestruct
2 implementations
JSON Encoding Libraries
encoding/json vs goccy/go-json vs json-iterator vs sonic.
jsonencodingmarshalunmarshal+2
4 implementationsup to 7.8x difference
JSON Struct vs Map
Comparing JSON serialization performance between typed structs and generic maps (map[string]any).
jsonserializationstructmap+1
2 implementationsup to 4.0x difference
Map Lookup vs Slice Search
When does a map actually beat a linear slice search for membership tests?
mapslicelookupmembership+2
2 implementationsup to 103x difference
Mutex vs RWMutex vs Atomic
Which synchronization primitive should guard a shared value?
mutexrwmutexatomicsync+2
3 implementationsup to 2.6x difference
Printing
Compare fmt's Print, Printf, and Println variants, with and without a target writer.
fmtprintio
6 implementationsup to 6.4x difference
Random Number Generation
math/rand vs math/rand/v2 vs crypto/rand for "I just need a random int".
randrandommath-randcrypto-rand+2
3 implementationsup to 46x difference
Regexp vs Manual String Validation
Precompiled regexp, inline regexp, and hand-rolled string checks compared.
regexpregexstringsvalidation+2
3 implementationsup to 613x difference
Slice Preallocation
How much does preallocating slice capacity actually save?
sliceappendpreallocationmake+2
3 implementationsup to 3.6x difference
sort.Slice vs slices.Sort
The old sort package against the generic slices package — same algorithm, different dispatch.
sortslicesgenericssort-slice+2
4 implementationsup to 3.4x difference
String Concatination
Comparing string concatenation approaches in Go, from the naive + operator to strings.Builder and beyond.
stringconcatinationappendbuilder+1
4 implementationsover 1000x difference
String Matching
Compare string matching approaches in Go.
stringsmatchingregexpregex+1
3 implementationsup to 64x difference
String to Bytes Conversion
The cost of []byte(s) and string(b) — and the unsafe zero-copy alternative.
stringbytesconversionunsafe+2
2 implementationsup to 47x difference
Struct Copy vs Pointer
Does passing structs by pointer actually make your code faster?
structpointercopyescape-analysis+2
6 implementationsup to 538x difference
sync.Pool Buffer Reuse
Allocating a fresh buffer every time vs reusing one from sync.Pool.
sync-poolbufferallocationgc+2
2 implementationsup to 13x difference
Time Format vs AppendFormat
Formatting timestamps with a fresh string vs appending into a reused buffer.
timeformatappendformatallocation+2
2 implementationsup to 1.8x difference
Type Assertions
Comparing type assertion, type switch, reflection, and comma-ok checks on interfaces.
type-assertiontype-switchreflectioninterface
4 implementationsup to 2.5x difference
WaitGroup vs Errgroup vs Semaphore
What the popular goroutine fan-out patterns cost per batch of tasks.
waitgrouperrgroupsemaphoregoroutines+2
3 implementations

How the numbers are made

Each comparison is a plain Go benchmark. The source for every implementation lives in the open repository and is shown on its page, so you can check exactly what was measured or run it yourself.

A small CLI runs every suite with go test -bench . -benchmem across several input sizes and CPU counts (1 to 32 cores) on the same machine, currently an AMD Ryzen 9 9950X3D 16-Core Processor. The raw output is parsed into JSON and this site is rebuilt from it. No number on these pages is typed in by hand.

Keep in mind these are microbenchmarks: they tell you the relative cost of one pattern against another, not how your whole program will behave. When results are within a few percent of each other, treat them as a tie.