(Go)不要使用append插入元素

Begosu · 2016-11-22 04:00:05

这个测试本身存在歧义,copyInsert使用了反射,这个理应效率不如append, 主要涉及到append内存分配的原理 append(slice[:1], append([]int{i}, slice[1:]...)...) 这块代码每次都会重新分配内存而且越来越大 append(slice, 1) 这样每次append只有slice容量不够的时候重新分配,而且分配的成本更低

应该这么测试:

import (
    "fmt"
    "reflect"
    "time"
)

func copyInsert(slice interface{}, pos int, value interface{}) interface{} {
    v := reflect.ValueOf(slice)
    v = reflect.Append(v, reflect.ValueOf(value))
    reflect.Copy(v.Slice(pos+1, v.Len()), v.Slice(pos, v.Len()))
    v.Index(pos).Set(reflect.ValueOf(value))
    return v.Interface()
}

func Insert(slice interface{}, pos int, value interface{}) interface{} {

    v := reflect.ValueOf(slice)

    ne := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(value)), 1, 1)

    ne.Index(0).Set(reflect.ValueOf(value))
    v = reflect.AppendSlice(v.Slice(0, pos), reflect.AppendSlice(ne, v.Slice(pos, v.Len())))

    return v.Interface()
}
func main() {
    t0 := time.Now()
    for i := 1; i < 10000000; i++ {
        slice := []int{1, 2}
        slice = append(slice[:1], append([]int{i}, slice[1:]...)...)
    }
    t1 := time.Now()
    for i := 1; i < 10000000; i++ {
        slice2 := []int{1, 2}
        slice2 = Insert(slice2, 1, i).([]int)
    }

    t2 := time.Now()
    for i := 1; i < 10000000; i++ {
        slice3 := []int{1, 2}
        slice3 = copyInsert(slice3, 1, i).([]int)
        //  fmt.Println(slice3)
    }

    t3 := time.Now()


    fmt.Println("reflect append insert:", t2.Sub(t1), "append insert: ", t1.Sub(t0), "copy Insert: ", t3.Sub(t2))
}

结果是: reflect append insert: 7.905349514s append insert: 694.886461ms copy Insert: 4.285007592s

#1