gpt4 book ai didi

go - sync.Mutex 和 *sync.Mutex 哪个更好?

转载 作者:数据小太阳 更新时间:2023-10-29 03:03:19 26 4
gpt4 key购买 nike

在 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 有什么区别,哪个更好?

最佳答案

comment from mkopriva 是正确的,应该是公认的答案。

但是,阅读 OP 的问题,我认为可能存在一个值得扩展的潜在误解:OP 提到唯一的区别是“一个必须初始化,另一个不需要”。
指向 TT 的指针之前的根本区别意味着在使用变量时会发生一系列行为变化,其中只有一个是它的实例化。

首先:两种情况下都存在实际的实例化。在 T 的情况下,它隐含在声明中,因为变量包含实例本身(可以这么说)。但是在指针的情况下,它可能发生在代码中完全不同的地方,因为变量只包含对实例的间接访问。这解释了为什么只有指针变体会导致“零指针取消引用”:只有在这种情况下,您的代码才能在变量实际初始化之前尝试对变量执行任何操作。

其次:使用具体的 T 以及 go 是 "pass by value" language 的事实,意味着每次调用都会复制任何具体的函数参数(或方法接收器)。
这至少会在三个方面产生影响:

  • 性能:如果被复制的实例是大型struct|,并且调用发生在您应用程序的热路径中,您将复制大量数据。
  • 内存使用:与上一点类似:如果您有长时间运行的 goroutines 接收大型 struct|s,这些副本可能会对您的应用程序的内存占用产生影响。
  • 语义:这可以说是最重要的区别:如果您的类型具有应该修改其内容的方法,那么您几乎必须使用指针接收器。否则,该方法将作用于一个副本,而更改将是不可见的。推论同样重要:如果您想表明您的方法不会修改它们的接收器,使用具体类型(可能具有未导出的内容)是实现该目的的好方法。

最后,这将我们带到了 sync.Mutex 的具体案例:查看上面的几点和代码,我们可以看到性能和内存使用通常不是问题,因为 sync.Mutex is a pretty small struct
然而,最后一点非常重要:有一个指向sync.Mutex 的指针是什么意思?这意味着包含 struct 的副本将指向同一个锁。即:这意味着您的 struct 的两个实例可能共享一个锁。
由于 go vet 不会提示将 pointers 复制到互斥量,因此复制您的父级 struct 不会引起警钟,您最终可能会保护两个独立的具有相同锁的实例,可能导致死锁。

总结:除非你知道你想用同一个锁保护不同的副本(恕我直言不太可能),你最好使用具体的sync.Mutex|是的。
如果制作 sync.Mutex 指针的唯一原因是因为 go vet 告诉您不要复制它,那么您可能应该考虑在 上查找一层struct 你试图保护:很可能你是通过有一个像

这样的具体接收者无意中复制它的
func (t T) foo(){...}

你应该去的地方

func (t *T) foo(){...}

关于go - sync.Mutex 和 *sync.Mutex 哪个更好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49808622/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com