Golang Whitch中的sync.Mutex和* sync.Mutex更好吗?

时间:2018-04-13 02:56:56

标签: go mutex

在Golang,我们可以使用:

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需要实例化才能使用。

Golang中sync.Mutex*sync.Mutex之间有什么区别?哪个更好?

3 个答案:

答案 0 :(得分:1)

  • 我认为你可以将* sync.Mutex视为一个简单的指针。如果你想 要使用它,你应该声明并初始化它,但如果你使用sync.Mutex, 它已被引入。
  • BTW,在k8s源代码中,它们总是传递变量指针使用,因为传递struct会做一个副本,但是如果使用指针, 你需要传递的只是一个指针。 (我的意思是你不需要复制支出)。

答案 1 :(得分:1)

comment from mkopriva是正确的,应该是可以接受的答案。

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

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

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

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

最后,这将我们引到sync.Mutex的具体情况:通过以上几点和代码,我们可以看到性能和内存使用率通常不是问题,因为sync.Mutex is a pretty small struct。 br /> 但是,最后一点 非常重要:指向sync.Mutex的指针 是什么意思?这意味着包含struct的副本将指向相同的锁。即:这意味着您的struct的两个实例可能会共享一个锁。
由于go vet不会抱怨将 pointers 复制到互斥锁,因此复制父struct不会引起警告,您可能最终会保护两个具有相同锁的单独实例,这可能导致僵局。

总之:除非您知道,否则要保护具有相同锁的东西的不同副本(恕我直言不太可能),否则最好使用具体的sync.Mutex | es。< br /> 如果制作sync.Mutex指针的唯一原因是因为go vet告诉您不要复制它,那么您可能应该考虑在您要保护的struct上向上看一层:可能是由于使用

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

您应该在的地方

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

答案 2 :(得分:0)

它们并不完全相同:

  • sync.Mutex:在这里你可以直接使用Lock的{​​{1}}函数。

  • *sync.Mutex:这里你必须在使用函数之前进行初始化,就像你想从其他对象复制实例一样,因为如果你尝试使用上面的方式(没有指针)从其他对象复制它会向您显示警告 Unlock,您可以在 this answer 中找到它的解决方案。

  • 但是这两种类型都接受您使用函数 assignment copies lock value to xxxxxx: sync.Mutex copylocksLock 因为函数被声明为 Pointer receivers 并且这种声明函数的方式接受直接使用在一个对象或一个指针上,比如你所拥有的