分享
  1. 首页
  2. 文章

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

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

标题好像有点唬人哦....
起因是我在给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

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

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏