Golang Go语言中 &struct{} vs struct{} 应该如何选择?
有两个数据结构( struct ),就像下面这样:
// 1 type Struct1 struct { String string }type Structs1 []*Struct1 // Difference
type Test1Struct struct { S Structs1 }
// 2 type Struct2 struct { String string }
type Structs2 []Struct2 // Difference
type Test2Struct struct { S Structs2 }
他们的不同之处在于一个存的是struct
的Pointer
,另一个存的是struct
的Value
。
我做了一些测试,(似乎)表明使用Pointer
的时候要比使用Value
的时候更快:
[rain[@localhost](/user/localhost) valuevspointor]$ go test -test.bench . testing: warning: no tests to run PASS Benchmark1Pointer-2 5 229612872 ns/op Benchmark2Value-2 1 1367639458 ns/op Benchmark3HugeSetPointer-2 1 1100069534 ns/op Benchmark4HugeSetValue-2 1 4037397573 ns/op ok _/home/rain/Develpment/Meta/valuevspointor 10.775s
(当然这个测试说不定是有问题的,代码: https://gist.github.com/raincious/b70e17abfd08f4764683 )
按照上面的测试,想要建立一个新的 struct 应该优先使用&struct{}
而不是struct{}
,那么问题来了,如果是这样的话,struct{}
的意义何在?
或者应该问:如何决定应该使用&struct{}
还是struct{}
?
(比如在需要注意性能和 GC 的情况下)
感谢。
Golang Go语言中 &struct{} vs struct{} 应该如何选择?
更多关于Golang Go语言中 &struct{} vs struct{} 应该如何选择?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
一个值被传递的时候会被复制,也就是如果是指针,就复制指针,如果是 struct ,就复制整个 struct.
建立一个&struct{}会先建立一个 struct{},在建立一个指针指向他
遍历一个[]*struct{} 会访问一串连续的指针,访问每个指针的时候会随机访问到这个指针指向的地址, GC 也是一样的道理。
孰轻孰重,这个就要靠你自己去判断了。
更多关于Golang Go语言中 &struct{} vs struct{} 应该如何选择?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在考虑性能的情况下,需要考虑你的使用模式是否是缓存友好的。
指针占用空间小,拷贝代价小,但是访问数据需要一次间接跳转,并不是缓存友好的。
struct 存在拷贝代价,但是使用时是缓存友好的。
在拥有多级缓存的现代 cpu 上,栈上的变量有很大可能完全位于缓存中,以至于小尺寸 struct 拷贝速度非常快。但指针所使用的内存可能并没有被预读到缓存中,这将导致使用指针变量反而更慢。
在这篇文章中有一段
https://talks.golang.org/2012/splash.article
The key point is that Go gives the programmer tools to limit allocation by controlling the layout of data structures. Consider this simple type definition of a data structure containing a buffer (array) of bytes:
type X struct {
a, b, c int
buf [256]byte
}
In Java, the buf field would require a second allocation and accesses to it a second level of indirection. In Go, however, the buffer is allocated in a single block of memory along with the containing struct and no indirection is required. For systems programming, this design can have a better performance as well as reducing the number of items known to the collector. At scale it can make a significant difference.
可以间接说明这个问题,通过指针间接访问变量是有代价的。
至于你的测试可能还不足以说明问题,因为 string 需要支持不同长度,肯定在内部实现上需要动态内存的,因此也就是一定存在间接访问。你需要做的测试需要对比 struct 成员全部是固定大小。一个紧凑的,连续累加 int 的测试或许可以有非常大的差异。至于指针更快还是 struct 更快取决于你的内存访问模式。如果是大数据(比如超过 cpu 二级缓存大小)拷贝为主,那就选指针。如果是连续访问元素,那么就应该选 struct
通常情况下,简单的回答是,如果 struct 很大,用指针更快,反之用值更快
但什么是 “很大”,显然不容易判断
所以我的观点是,上面说的都没什么用
如果要在意这个性能,就分别做性能测试,哪个快用哪个
在Go语言中,&struct{}
和 struct{}
的选择取决于具体的使用场景和需求。
-
内存占用:
struct{}
是一个空结构体实例,它本身不占用除结构体本身以外的额外内存空间(在大多数实现中,空结构体实例的内存占用可以忽略不计)。&struct{}
是一个指向空结构体实例的指针。虽然空结构体实例本身占用很少的内存,但指针本身需要一定的内存空间来存储地址信息。
-
使用场景:
struct{}
常用于需要一个占位符或仅表示某种状态但不携带任何数据的场景。例如,在需要返回一个空值但又不想使用nil
或interface{}
时,可以使用struct{}
。&struct{}
常用于需要传递或存储结构体指针的场景。例如,在通道(channel)中传递空结构体指针以表示某种信号或事件时,使用&struct{}
可以避免拷贝结构体实例,提高效率。
-
性能考虑:
- 在性能敏感的场景中,如果不需要指针的间接引用功能,直接使用
struct{}
可能更为高效,因为它避免了指针的额外开销。 - 在需要动态访问或修改结构体内容的场景中,使用指针
&struct{}
是必要的。
- 在性能敏感的场景中,如果不需要指针的间接引用功能,直接使用
综上所述,选择 &struct{}
还是 struct{}
应根据具体需求来决定。如果仅需要一个占位符且不需要指针功能,struct{}
是一个不错的选择;如果需要指针的灵活性或效率上的考虑(如通道通信),则 &struct{}
可能更为合适。