Golang 里面选择 []T 还是 []*T?

2020-04-21 13:23:58 +08:00
 wangbenjun5

我看到公司项目里面无论是方法参数还是返回值全部都是*T,也就是都是指针

根据很多文章介绍,Go 里面只存在值传递,但是如果作为函数返回值来用,加个指针意义何在?

func something()([]*T) {

}

经过我测试,加上指针后内存分配的次数反而多了,性能有所下降

5529 次点击
所在节点    程序员
33 条回复
leoleoasd
2020-04-21 13:26:10 +08:00
大结构体防止拷贝?
Wirbelwind
2020-04-21 13:37:40 +08:00
golang 不是 gc 语言吗 难道不是引用语义?
maichael
2020-04-21 13:38:33 +08:00
unixeno
2020-04-21 13:39:34 +08:00
大结构体用指针能减少内存拷贝的时间
maichael
2020-04-21 13:40:15 +08:00
我的看法是取决于你的用途。
wangbenjun5
2020-04-21 13:54:03 +08:00
@maichael 看了链接里面,最终好像也没什么结论,如果按很多文章的说法,那不如统一都加指针,毕竟指针比非指针“多”一些用途
keepeye
2020-04-21 13:56:26 +08:00
一直用[]*T 无论 T 多大
boboliu
2020-04-21 13:58:34 +08:00
你们都不用 interface 么
fanhed
2020-04-21 13:59:54 +08:00
一般来说, 无脑用*T 就好了
warlock
2020-04-21 14:04:02 +08:00
复杂结构用指针可以减少拷贝 简单结构不用指针可以提升 GC 性能
matrix67
2020-04-21 14:05:07 +08:00
之前印象笔记收藏的:


我们通过一些代码示例来演示了在 Go 中值类型和指针类型的一些具体表现,最后我们要回答这么几个问题,希望你能够在使用 Go 编程的过程中更加清晰的掌握这些技巧。Receiver Type 为什么推荐使用指针?

* 推荐在实例方法上使用指针(前提是这个类型不是一个自定义的 map 、slice 等引用类型)
* 当结构体较大的时候使用指针会更高效
* 如果要修改结构内部的数据或状态必须使用指针
* 当结构类型包含 sync.Mutex 或者同步这种字段时,必须使用指针以避免成员拷贝
* 如果你不知道该不该使用指针,使用指针!

“结构较大” 到底多大才算大可能需要自己或团队衡量,如超过 5 个字段或者根据结构体内占用来计算。方法参数该使用什么类型?
* map 、slice 等类型不需要使用指针(自带 buf )
* 指针可以避免内存拷贝,结构大的时候不要使用值类型
* 值类型和指针类型在方法内部都会产生一份拷贝,指向不同
* 小数据类型如 bool 、int 等没必要使用指针传递
* 初始化一个新类型时(像 NewEngine() *Engine )使用指针
* 变量的生命周期越长则使用指针,否则使用值类型

- 不用指针是值传递,基本就不会走 gc,缺点是导致整个 struct 发生内存拷贝,当然被编译器识别为 inline 函数就什么都不会发生,快得一匹。当你函数输入 /返回参数,struct 就几个 int,float,值传递吧!

- 指针就是类似引用传递,出作用域会走 gc,当然也不是绝对,比如 inline 函数返回指针就不一定会导致堆分配,当然内置的 new 和 make,map,slice 等本身就分配在堆上就必然走 gc 。

- gc 对于密集型计算服务的后果就是大量 cpu 计算都消耗在 gc 上,严重影响性能,另外栈内存的分配花销时间可能比堆好

- 其实在 Go 中,除了方法属主参数,指针使用的并不普遍,使用指针参数的主要目的是在函数内能够更改此指针所引用的值。指针有时候也用来避免较大的值赋值代价。比如将一个指针包裹在接口值中的代价比将一个非接口值包裹到接口值中的代价小得多。另一方面,过多的指针会影响垃圾回收的时长,一般这种情况发生在一个容器中含有大量包含指针的元素。
lhx2008
2020-04-21 14:06:27 +08:00
楼主的例子,你测试的值传递传递是切片,又不是传数组,所以数组根本没被复制。。。和你用不用内部指针就更没关系
ethego
2020-04-21 14:10:38 +08:00
slice 里本来就是指针,你这样写传的是指针的指针。
lhx2008
2020-04-21 14:10:47 +08:00
要说也是 append 进切片的时候会有一次复制,如果你是指针的话复制的东西比较少,但是后面再用的时候都是复制的是切片了。。
ethego
2020-04-21 14:11:02 +08:00
自己用逃逸分析看看就知道了
whahuzhihao
2020-04-21 14:11:50 +08:00
其实传参时用非指针的 T,能提高 GC 效率
CEBBCAT
2020-04-21 14:13:29 +08:00
slice 是两级结构,一层是切片的描述如容量和长度及数组的指针,下层是被上层指向的数组。这样的区别可能是减低数组扩容复制时的时间开销吧,另外这样可能也有一点点加速垃圾回收的考虑?

我是新手(上海及南方求 Go 坑位)
ethego
2020-04-21 14:17:20 +08:00
@lhx2008 只要有 append 进 slice 的操作,被操作实例几乎必逃逸,所以复制也只是复制的指针而已
zdt3476
2020-04-21 14:22:49 +08:00
无脑用指针,等需要优化的时候再改就好了。
simenet
2020-04-21 14:25:34 +08:00
别问 问就是无脑 *T

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/664610

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX