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

深度拷贝可以通过序列化和反序列化来实现,也可以基于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 语言对象深拷贝方式性能分析_第1张图片

深拷贝内存分析

Go 语言对象深拷贝方式性能分析_第2张图片

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

你可能感兴趣的:(Go语言编程)