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

And*_*son 11 mutex go

在 Go 中,我们可以使用:

type Data struct {
    lock  *sync.Mutex
}
Run Code Online (Sandbox Code Playgroud)

或者

type Data struct {
    lock  sync.Mutex
}
Run Code Online (Sandbox Code Playgroud)

并且,像这样使用:

func (d *Data) Update() {
   d.lock.Lock()
   defer d.lock.Unlock()
   // update
}
Run Code Online (Sandbox Code Playgroud)

我能想到的区别是只*sync.Mutex需要实例化即可使用。

是什么区别sync.Mutex*sync.Mutex围棋,哪一个更好?

Leo*_*nes 13

mkopriva 的评论是正确的,可能应该是公认的答案。

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

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

其次:使用具体T以及 go 是一种“按值传递”语言这一事实​​,意味着每次调用都会复制任何具体的函数参数(或方法接收者)。
这至少会在三个方面产生影响:

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

最后,这将我们引向具体的情况sync.Mutex:查看上面的要点和代码,我们可以看到性能和内存使用通常不是问题,因为sync.Mutex是一个非常小的struct.
然而,最后一点非常重要:指向 a 的指针意味着什么sync.Mutex?这意味着包含的副本struct将指向同一个锁。即:这意味着您的两个实例struct可能共享一个锁。
由于go vet不会抱怨复制指向互斥体的指针,因此复制父级struct不会引起警钟,并且您最终可能会使用同一锁保护两个单独的实例,从而可能导致死锁。

总之:除非您知道您想使用同一锁保护某些内容的不同副本(恕我直言,不太可能),否则最好使用具体的sync.Mutex|es。
如果创建指针的唯一原因sync.Mutex是告诉您不要复制它,那么您可能应该考虑在您试图保护的对象 go vet上查找一层:很可能您通过使用像这样的具体接收器无意中复制了它struct

func (t T) foo(){...}
Run Code Online (Sandbox Code Playgroud)

你应该在哪里

func (t *T) foo(){...}
Run Code Online (Sandbox Code Playgroud)


Mau*_*ken 4

  • 我认为你可以将 *sync.Mutex 视为一个简单的指针。如果你想使用它,你应该声明并初始化它,但如果你使用sync.Mutex,它已经被初始化了。
  • 顺便说一句,在 k8s 源代码中,它们总是传递变量指针来使用,因为传递 struct 会进行复制,但如果您使用指针,则只需传递一个指针即可。(我的意思是你不需要复制花费)。

  • “我认为这是编程的一个很好的实践”——除非它不是:指针的语义是关于共享所有权的,它不是一个性能优化工具。仅仅因为“我喜欢它”或“有人推荐它”而使用指针是没有意义的。 (6认同)
  • “参数太大的话,后面会更快。” ——这真是一个可怕的结论。尺寸并不是唯一需要考虑的因素。指针值是要在堆上分配的候选值,这意味着 GC 压力,这不是免费的。因此,如果没有分析/基准测试,就永远不能说指针比原始值更好。 (4认同)
  • @Anderson 指针或非指针与 `sync.Mutex` 并发使用的安全性无关。私有或公共变量与指针与非指针的使用无关。无论您是否使用指针,您的“Update”方法都将以完全相同的方式工作。 (2认同)