GolangNote

Golang笔记

Golang 两个同类型 struct 的比较的方法及性能

Permalink

比较两个同类型 struct 是否相等,可以用 reflect.DeepEqualcmp.Equal,也可以使用硬编码比较,下面看看它们的性能如何。

Golang 两个同类型 struct 的比较的方法及性能

定义一个有多种数据类型的 struct,如:

Go: 定义 struct
1
2
3
4
5
6
type T struct {
	X int
	Y string
	Z []int
	M map[string]string
}

reflect.DeepEqual

这是内置的函数

Go: reflect.DeepEqual
1
reflect.DeepEqual(t2, t1)

cmp.Equal

引入库 github.com/google/go-cmp/cmp

Go: cmp.Equal
1
cmp.Equal(t2, t1)

硬编码比较

对一种特定的 struct 比较,

Go: 比较 struct
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
func customEqual(t1, t2 T) bool {
	if t1.X != t2.X {
		return false
	}
	if t1.Y != t2.Y {
		return false
	}

	if len(t1.Z) != len(t2.Z) {
		return false
	}
	for i, v := range t1.Z {
		if t2.Z[i] != v {
			return false
		}
	}
	if len(t1.M) != len(t2.M) {
		return false
	}
	for k := range t1.M {
		if t2.M[k] != t1.M[k] {
			return false
		}
	}

	return true
}

性能测试代码

Go: struct 比较
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package main

// go test -v cmp_test.go -bench "Benchmark" -benchmem

import (
	"reflect"
	"testing"

	"github.com/google/go-cmp/cmp"
)

type T struct {
	X int
	Y string
	Z []int
	M map[string]string
}

var (
	t1 = T{
		X: 1,
		Y: "lei",
		Z: []int{1, 2, 3},
		M: map[string]string{
			"a": "111112222",
			"c": "9",
			"b": "2222",
		},
	}

	t2 = T{
		X: 1,
		Y: "lei",
		Z: []int{1, 2, 3},
		M: map[string]string{
			"a": "111112222",
			"c": "9",
			"b": "3333",
		},
	}
)

func customEqual(t1, t2 T) bool {
	if t1.X != t2.X {
		return false
	}
	if t1.Y != t2.Y {
		return false
	}

	if len(t1.Z) != len(t2.Z) {
		return false
	}
	for i, v := range t1.Z {
		if t2.Z[i] != v {
			return false
		}
	}
	if len(t1.M) != len(t2.M) {
		return false
	}
	for k := range t1.M {
		if t2.M[k] != t1.M[k] {
			return false
		}
	}

	return true
}

func customEqual2(t1, t2 T) bool {
	if t1.X != t2.X {
		return false
	}
	if t1.Y != t2.Y {
		return false
	}

	if len(t1.Z) != len(t2.Z) {
		return false
	}
	for i, v := range t1.Z {
		if t2.Z[i] != v {
			return false
		}
	}
	if len(t1.M) != len(t2.M) {
		return false
	}
	for k := range t1.M {
		if t2.M[k] != t1.M[k] {
			return false
		}
	}

	return true
}

func Benchmark_reflect_DeepEqual(b *testing.B) {
	b.ResetTimer()
	defer b.StopTimer()
	for i := 0; i < b.N; i++ {
		reflect.DeepEqual(t2, t1)
	}
}

func Benchmark_cmp_Equal(b *testing.B) {
	b.ResetTimer()
	defer b.StopTimer()
	for i := 0; i < b.N; i++ {
		cmp.Equal(t2, t1)
	}
}

func Benchmark_custom_Equal(b *testing.B) {
	b.ResetTimer()
	defer b.StopTimer()
	for i := 0; i < b.N; i++ {
		customEqual(t2, t1)
	}
}

测试结果

plaintext: 测试结果
1
2
3
4
5
6
7
8
9
10
11
goos: darwin
goarch: amd64
cpu: Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz
Benchmark_reflect_DeepEqual
Benchmark_reflect_DeepEqual-8   	  688875	      1595 ns/op	     483 B/op	      18 allocs/op
Benchmark_cmp_Equal
Benchmark_cmp_Equal-8           	  139269	      8421 ns/op	    2840 B/op	      52 allocs/op
Benchmark_custom_Equal
Benchmark_custom_Equal-8        	10542481	       111.9 ns/op	       0 B/op	       0 allocs/op
PASS

从实行时间上看,耗时比较:

plaintext: 耗时比较
1
cmp.Equal > reflect.DeepEqual * 5 > customEqual * 75

如果程序只对固定的 struct 做是否相等的比较,追求性能就考虑自己写比较函数。

本文网址: https://golangnote.com/topic/300.html 转摘请注明来源

Related articles

Golang Range 的性能提升Tip

Go 语言里使用 range 可以方便遍历数组(array)、切片(slice)、字典(map)和信道(chan)。这里主要关注他们的性能。...

Golang 泛型性能初识

编程时,我们通常需要编写“泛型”函数,其中确切的数据类型并不重要。例如,您可能想编写一个简单的函数来对数字进行求和。Go 直到最近才有这个概念,但最近才添加了它(从1.18版开始)。...

Write a Comment to "Golang 两个同类型 struct 的比较的方法及性能"

Submit Comment Login
Based on Golang + fastHTTP + sdb | go1.20 Processed in 1ms