英文:
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.)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论