在Go语言中,你什么时候将互斥锁(mutex)嵌入到结构体中?

huangapple go评论152阅读模式
英文:

When do you embed mutex in struct in Go?

问题

我看到很多代码都这样写:

type A struct {
    mu sync.Mutex
    ...
}

然后像这样使用:

a := &A{}

a.mu.Lock()
defer a.mu.Unlock()

a.Something()

这种方式比使用局部互斥锁或全局互斥锁更好吗?

a := &A{}

var mu sync.Mutex
mu.Lock()
defer mu.Unlock()

a.Something()

我应该在什么时候使用前者,或者后者?

英文:

NOTE: I found the word 'embed' in the title was bad choice, but I will keep it.

I see a lot of code does like this:

type A struct {
    mu sync.Mutex
    ...
}

And use it like this:

a := &A{}

a.mu.Lock()
defer a.mu.Unlock()

a.Something()

Is it better than local mutex or global mutex?

a := &A{}

var mu sync.Mutex
mu.Lock()
defer mu.Unlock()

a.Something()

When should I use former, or later?

答案1

得分: 71

将互斥锁(mutex)放在需要保护的数据附近是一个很好的实践。如果一个互斥锁需要保护结构体字段的并发访问,将互斥锁作为该结构体的一个字段非常方便,这样它的用途就很明显。

如果你的应用程序只有一个A的实例,将互斥锁作为全局变量也是可以的。

如果你的应用程序需要创建多个A的值,并且所有这些值都需要保护免受并发访问(但只是单独地保护,多个值可以同时访问),那么显然全局互斥锁是一个糟糕的选择,它会限制在任何时间点上对单个A值的并发访问。

将互斥锁作为结构体的一个字段,你将自然地为每个不同的结构体值拥有一个单独的互斥锁,负责保护该单个的包装结构体值(或其字段)。

尽管在你的示例中添加互斥锁并不是嵌入式的,它是一个常规的、有名称的字段。嵌入式字段声明省略了字段名。

人们对此了解和使用的程度较少,但也很方便的是,你可以在结构体中“真正”地嵌入一个互斥锁,并且可以像调用结构体自身的方法一样调用Lock()Unlock()。示例如下:

var hits struct {
    sync.Mutex
    n int
}

hits.Lock()
hits.n++
hits.Unlock()

(此示例摘自10 things you (probably) don't know about Go, slide #3。)

英文:

It's good practice to keep the mutex close to the data it is destined to protect. If a mutex ought to protect concurrent access to fields of a struct value, it's very convenient to add the mutex as a field of that struct, so its purpose is obvious.

If in your app there is only a single "instance" of A, it's fine to make the mutex a global variable too.

If your app is to create multiple values of A, all of which needs to be protected from concurrent access (but only individually, multiple values may be accessed concurrently), then obviously a global mutex is a bad choice, it would limit the concurrent access to a single value of A in any point in time.

Adding the mutex to the struct as a field, you will naturally have a separate mutex for each distinct struct values, responsible to guard that single, wrapper struct value (or its fields).

Although adding a mutex as in your example is not embedding, it's a regular, named field. An embedded field declaration omits the field name.

It's known and used to a lesser extent, but it's also handy that you can "truly" embed a mutex in a struct, and you can call Lock() and Unlock() as if they would be part of the struct itself. It looks like this:

var hits struct {
    sync.Mutex
    n int
}

hits.Lock()
hits.n++
hits.Unlock()

(This example is taken from 10 things you (probably) don't know about Go, slide #3.)

huangapple
  • 本文由 发表于 2017年7月6日 20:53:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/44949467.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定