Go 语言对象深拷贝方式性能分析

Viridis ·
更新时间:2024-11-13
· 735 次阅读

深度拷贝可以通过序列化和反序列化来实现,也可以基于reflect包的反射机制完成。我对于这两种方式实现深拷贝做了性能基准测试。

下面是对比反射(github.com/mohae/deepcopy)与序列化(gob)所用的基准测试脚本 deepcopy_test.go

package deepcopy import ( "bytes" "encoding/gob" "testing" "github.com/mohae/deepcopy" ) type Basics struct { String string Strings []string StringArr [4]string Bool bool Bools []bool Byte byte Bytes []byte Int int Ints []int Int8 int8 Int8s []int8 Int16 int16 Int16s []int16 Int32 int32 Int32s []int32 Int64 int64 Int64s []int64 Uint uint Uints []uint Uint8 uint8 Uint8s []uint8 Uint16 uint16 Uint16s []uint16 Uint32 uint32 Uint32s []uint32 Uint64 uint64 Uint64s []uint64 Float32 float32 Float32s []float32 Float64 float64 Float64s []float64 Complex64 complex64 Complex64s []complex64 Complex128 complex128 Complex128s []complex128 Interface interface{} Interfaces []interface{} } var src = Basics{ String: "kimchi", Strings: []string{"uni", "ika"}, StringArr: [4]string{"malort", "barenjager", "fernet", "salmiakki"}, Bool: true, Bools: []bool{true, false, true}, Byte: 'z', Bytes: []byte("abc"), Int: 42, Ints: []int{0, 1, 3, 4}, Int8: 8, Int8s: []int8{8, 9, 10}, Int16: 16, Int16s: []int16{16, 17, 18, 19}, Int32: 32, Int32s: []int32{32, 33}, Int64: 64, Int64s: []int64{64}, Uint: 420, Uints: []uint{11, 12, 13}, Uint8: 81, Uint8s: []uint8{81, 82}, Uint16: 160, Uint16s: []uint16{160, 161, 162, 163, 164}, Uint32: 320, Uint32s: []uint32{320, 321}, Uint64: 640, Uint64s: []uint64{6400, 6401, 6402, 6403}, Float32: 32.32, Float32s: []float32{32.32, 33}, Float64: 64.1, Float64s: []float64{64, 65, 66}, Complex64: complex64(-64 + 12i), Complex64s: []complex64{complex64(-65 + 11i), complex64(66 + 10i)}, Complex128: complex128(-128 + 12i), Complex128s: []complex128{complex128(-128 + 11i), complex128(129 + 10i)}, Interfaces: []interface{}{42, true, "pan-galactic"}, } func Benchmark_GOBDeepCopy(b *testing.B) { // use b.N for looping for i := 0; i < b.N; i++ { var dst Basics err := GOBDeepCopy(&dst, &src) if err != nil { b.Error(err) } } } func Benchmark_ReflectDeepCopy(b *testing.B) { // use b.N for looping for i := 0; i < b.N; i++ { dst := deepcopy.Copy(src).(Basics) if !dst.Bool { b.Error("reflect deep copy failed") } } } // GOBDeepCopy provides the method to creates a deep copy of whatever is passed to // it and returns the copy in an interface. The returned value will need to be // asserted to the correct type. func GOBDeepCopy(dst, src interface{}) error { var buf bytes.Buffer if err := gob.NewEncoder(&buf).Encode(src); err != nil { return err } return gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(dst) }

进行持续时长为 10s 的基准测试并对 CPU 和内存使用情况做记录:

$ go test -v -run=^$ -bench=. -benchtime=10s -cpuprofile=prof.cpu -memprofile=prof.mem -memprofilerate=2 goos: darwin goarch: amd64 Benchmark_GOBDeepCopy-4 5000 2918910 ns/op Benchmark_ReflectDeepCopy-4 50000 289784 ns/op PASS ok _/Users/xuri/Desktop/deepcopy 32.421s

使用火焰图分析 CPU 情况

Go 语言对象深拷贝方式性能分析

深拷贝内存分析

Go 语言对象深拷贝方式性能分析

通过对比可以看出,反射比 gob 序列化来实现深拷贝速度快 10 倍,CPU 与内存的开销也更优。


作者:xurime



性能分析 GO 深拷贝 性能 对象 拷贝

需要 登录 后方可回复, 如果你还没有账号请 注册新账号