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 語言對象深拷貝方式性能分析

深拷貝內存分析

Go 語言對象深拷貝方式性能分析

通過對比可以看出,反射比 gob 序列化來實現深拷貝速度快 10 倍,CPU 與內存的開銷也更優。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章