在Go中,我们可以使用:
type Data struct {
lock *sync.Mutex
}或
type Data struct {
lock sync.Mutex
}然后,像这样使用:
func (d *Data) Update() {
d.lock.Lock()
defer d.lock.Unlock()
// update
}我能想到的不同之处是,*sync.Mutex只需要实例化即可使用。
sync.Mutex和*sync.Mutex在Go中有什么区别,哪一个更好?
发布于 2020-01-29 10:38:25
mkopriva的评论是正确的,应该是公认的答案。
然而,在阅读OP的问题时,我认为可能有一个潜在的误解值得扩展:OP提到唯一的区别是“一个必须初始化,另一个不需要初始化”。
指向T和T的指针之前的基本区别意味着在使用变量时一系列的行为更改,其中只有一个是它的实例化。
首先,在这两种情况下都存在实例化。在T情况下,它隐含在声明中,因为变量包含实例本身(可以这么说)。但是在指针的情况下,它可能发生在代码中完全不同的位置,因为变量只包含对实例的间接。这解释了为什么只有指针变量才能导致“零指针取消引用”:只有在这种情况下,您的代码才能尝试在变量实际初始化之前对其执行任何操作。
其次:使用一个具体的T,加上go是一个“通过价值”的语言,意味着每个调用都复制任何具体的函数参数(或方法接收者)。
这至少在三个方面产生了影响:
struct\s,并且调用发生在应用程序的热路径中,那么您将复制大量的数据。struct\s,这些副本可能会对应用程序的内存占用产生影响。最后,这就引出了sync.Mutex的具体案例:查看上面的要点和代码,我们可以看到性能和内存的使用通常不是一个问题,因为struct。
然而,最后一点非常重要:拥有指向sync.Mutex的指针意味着什么?这意味着包含struct的副本将指向同一个锁。也就是说,struct的两个实例可能共享一个锁。
由于go vet不会抱怨将指针复制到互斥对象,所以复制父struct不会引起警报,您可能最终会用相同的锁保护两个单独的实例,这可能会导致死锁。
总之:除非知道,否则您想要保护具有相同锁的东西的不同副本(IMHO有点不太可能),最好使用具体的sync.Mutex\es。
如果创建sync.Mutex指针的唯一原因是因为go vet告诉您不要复制它,那么您可能应该考虑在试图保护的struct上查找一层:很可能是通过一个具体的接收器(如
func (t T) foo(){...}你应该去的地方
func (t *T) foo(){...}发布于 2018-04-13 05:27:43
发布于 2021-07-30 22:11:20
https://stackoverflow.com/questions/49808622
复制相似问题