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

Begosu · · 7676 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

标题好像有点唬人哦….
起因是我在给Slice做Insert函数,给几个版本封装时做了一些性能测试。结果出人意料!

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() {
    slice := []int{1, 2}
    slice2 := []int{1, 2}
    slice3 := []int{1, 2}
    t0 := time.Now()
    for i := 1; i < 10000; i++ {
        slice = append(slice[:1], append([]int{i}, slice[1:]...)...)
    }
    t1 := time.Now()
    for i := 1; i < 10000; i++ {
        slice2 = Insert(slice2, 1, i).([]int)
    }

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

    t3 := time.Now()

    //元素检测
    for i := 0; i < 10000; i++ {
        if slice[i] != slice2[i] || slice2[i] != slice3[i] {
            fmt.Println("error")
        }
    }

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

输出结果

reflect append insert: 273.276271ms append insert:  195.938231ms copy Insert:  29.626058ms

利用反射的reflect比普通append尚可理解,但居然比copy Instert慢了10倍。>_<。

我不信啊,于是再做了测试


import (
    "fmt"
    "time"
)

func main() {
    s1 := []int{1, 2, 3}
    s2 := []int{1, 2, 3}

    //每次插入第三个
    t1 := time.Now()
    for i := 0; i < 10000; i++ {
        s1 = append(s1[0:3], append([]int{i}, s1[3:]...)...)
    }
    t2 := time.Now()
    //每次插入第三个
    for i := 0; i < 10000; i++ {
        s2 = append(s2, i)
        copy(s2[3:len(s2)], s2[2:len(s2)-1])
        s2[3] = i
    }

    t3 := time.Now()
    //检测错误
    for i := 0; i < len(s1); i++ {
        if s1[i] != s2[i] {
            fmt.Println("error")
        }
    }

    fmt.Println(t3.Sub(t2), t2.Sub(t1))
}

输出结果

copy instert: 21.245765ms append insert:  189.930674ms

结果还是差了十倍哎!

猜测:两次append()的时候,做slice切片会产生底层数组复制。(append([]int{i}, s1[3:]…)),但s1很大的时候,复制的越多,性能越差,而copy是利用原有的底层数组。>_<。

欢迎大牛指点….


有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:Begosu

查看原文:(Go)不要使用append插入元素

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

7676 次点击  
加入收藏 微博
1 回复  |  直到 1999-12-31 16:00:00
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传