Skip to content

Instantly share code, notes, and snippets.

@fishy
Last active March 30, 2019 01:09
Show Gist options
  • Save fishy/bca72d0d65ba35e9ab6b50f66f9fc42e to your computer and use it in GitHub Desktop.
Save fishy/bca72d0d65ba35e9ab6b50f66f9fc42e to your computer and use it in GitHub Desktop.
Go: bytes.Equal vs. reflect.DeepEqual (vs. self-implemented equal) (https://wang.yuxuan.org/blog/item/2017/02/comparing-byte-s-in-go)
package main_test
import (
"bytes"
"fmt"
"math/rand"
"os"
"reflect"
"testing"
"time"
)
var sizes = []int{
1024,
1024 * 1024,
64 * 1024 * 1024,
}
func TestMain(m *testing.M) {
rand.Seed(time.Now().Unix())
os.Exit(m.Run())
}
func BenchmarkEqual(b *testing.B) {
for _, size := range sizes {
b1 := make([]byte, size)
rand.Read(b1)
b2 := make([]byte, size)
copy(b2, b1)
b.Run(
fmt.Sprintf("reflect.DeepEqual-%d", size),
func(b *testing.B) {
for i := 0; i < b.N; i++ {
reflect.DeepEqual(b1, b2)
}
},
)
b.Run(
fmt.Sprintf("equal-%d", size),
func(b *testing.B) {
for i := 0; i < b.N; i++ {
equal(b1, b2)
}
},
)
b.Run(
fmt.Sprintf("bytes.Equal-%d", size),
func(b *testing.B) {
for i := 0; i < b.N; i++ {
bytes.Equal(b1, b2)
}
},
)
}
}
func BenchmarkNonEqual(b *testing.B) {
for _, size := range sizes {
b1 := make([]byte, size)
rand.Read(b1)
b2 := make([]byte, size)
rand.Read(b2)
b.Run(
fmt.Sprintf("reflect.DeepEqual-%d", size),
func(b *testing.B) {
for i := 0; i < b.N; i++ {
reflect.DeepEqual(b1, b2)
}
},
)
b.Run(
fmt.Sprintf("equal-%d", size),
func(b *testing.B) {
for i := 0; i < b.N; i++ {
equal(b1, b2)
}
},
)
b.Run(
fmt.Sprintf("bytes.Equal-%d", size),
func(b *testing.B) {
for i := 0; i < b.N; i++ {
bytes.Equal(b1, b2)
}
},
)
}
}
func TestEqual(t *testing.T) {
for _, size := range sizes {
b1 := make([]byte, size)
rand.Read(b1)
b2 := make([]byte, size)
rand.Read(b2)
b3 := make([]byte, size)
copy(b3, b1)
t.Run(
fmt.Sprintf("reflect.DeepEqual-%d", size),
func(t *testing.T) {
if reflect.DeepEqual(b1, b2) {
t.Error("reflect.DeepEqual(b1, b2) should return false")
}
if !reflect.DeepEqual(b1, b3) {
t.Error("reflect.DeepEqual(b1, b2) should return true")
}
},
)
t.Run(
fmt.Sprintf("equal-%d", size),
func(t *testing.T) {
if equal(b1, b2) {
t.Error("equal(b1, b2) should return false")
}
if !equal(b1, b3) {
t.Error("equal(b1, b2) should return true")
}
},
)
t.Run(
fmt.Sprintf("bytes.Equal-%d", size),
func(t *testing.T) {
if bytes.Equal(b1, b2) {
t.Error("bytes.Equal(b1, b2) should return false")
}
if !bytes.Equal(b1, b3) {
t.Error("bytes.Equal(b1, b2) should return true")
}
},
)
}
}
func equal(b1, b2 []byte) bool {
if len(b1) != len(b2) {
return false
}
for i, b := range b1 {
if b != b2[i] {
return false
}
}
return true
}
$ go test -bench=.
BenchmarkEqual/reflect.DeepEqual-1024-4 20000 91193 ns/op
BenchmarkEqual/equal-1024-4 3000000 544 ns/op
BenchmarkEqual/bytes.Equal-1024-4 50000000 22.6 ns/op
BenchmarkEqual/reflect.DeepEqual-1048576-4 20 89556304 ns/op
BenchmarkEqual/equal-1048576-4 3000 536891 ns/op
BenchmarkEqual/bytes.Equal-1048576-4 30000 44613 ns/op
BenchmarkEqual/reflect.DeepEqual-67108864-4 1 5801186044 ns/op
BenchmarkEqual/equal-67108864-4 30 37011544 ns/op
BenchmarkEqual/bytes.Equal-67108864-4 200 8574768 ns/op
BenchmarkNonEqual/reflect.DeepEqual-1024-4 5000000 280 ns/op
BenchmarkNonEqual/equal-1024-4 500000000 3.46 ns/op
BenchmarkNonEqual/bytes.Equal-1024-4 300000000 4.56 ns/op
BenchmarkNonEqual/reflect.DeepEqual-1048576-4 5000000 272 ns/op
BenchmarkNonEqual/equal-1048576-4 500000000 3.44 ns/op
BenchmarkNonEqual/bytes.Equal-1048576-4 300000000 4.52 ns/op
BenchmarkNonEqual/reflect.DeepEqual-67108864-4 5000000 269 ns/op
BenchmarkNonEqual/equal-67108864-4 500000000 3.42 ns/op
BenchmarkNonEqual/bytes.Equal-67108864-4 300000000 4.50 ns/op
PASS
ok _/Users/fishy/work/test 44.270s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment