英文:
Mutex - global or local and idiomatic usage?
问题
在阅读了golang.org和stackoverflow上的互斥锁示例之后,我仍然不确定关于匿名函数的声明和惯用用法。因此,我总结了一些示例。
A、B和C这几个示例是否几乎等效,还是有我没有注意到的重大差异?
我更喜欢全局示例"B"。我猜如果我小心使用它,它可能是最简单的解决方案。
或者也许有更好的使用互斥锁的方法吗?
package main
import (
"fmt"
"sync"
)
type MuContainer struct {
sync.RWMutex
data int
}
var mucglobal = &MuContainer{}
func main() {
// A: 全局声明 - 工作正常:添加45
for i := 0; i < 10; i++ {
go func(j int, mucf *MuContainer) {
mucf.Lock()
mucf.data += j
mucf.Unlock()
}(i, mucglobal)
}
// B: 仅全局 - 工作正常:添加45
for i := 0; i < 10; i++ {
go func(j int) {
mucglobal.Lock()
mucglobal.data += j
mucglobal.Unlock()
}(i)
}
// C: 局部声明 - 工作正常:添加45
muclocal := &MuContainer{}
for i := 0; i < 10; i++ {
go func(j int, mucf *MuContainer) {
mucf.Lock()
mucf.data += j
mucf.Unlock()
}(i, muclocal)
}
// // D: 指向结构体的指针 - 不工作:添加0
// // 我猜是因为它直接指向了结构体。
// for i := 0; i < 10; i++ {
// go func(j int, mucf *MuContainer) {
// mucf.Lock()
// mucf.data += j
// mucf.Unlock()
// }(i, &MuContainer{})
// }
for {
mucglobal.RLock()
muclocal.RLock()
fmt.Printf("global: %d / local: %d\n", mucglobal.data, muclocal.data)
if mucglobal.data == 90 && muclocal.data == 45 {
muclocal.RUnlock()
mucglobal.RUnlock()
break
}
muclocal.RUnlock()
mucglobal.RUnlock()
}
}
英文:
After reading the mutex examples on golang.org and stackoverflow, I'm still not sure about the declaration and idiomatic usage with anonymous functions. Therefore I've summarized a few examples.
Are examples A, B and C nearly equivalent or are there major differences that I don't notice?
I would prefer the global example "B". I guess if I'm careful with it, it's probably the simplest solution.
Or is there maybe a better approach to use mutex?
package main
import (
"fmt"
"sync"
)
type MuContainer struct {
sync.RWMutex
data int
}
var mucglobal = &MuContainer{}
func main() {
// A: Global declaration - working: adds 45
for i := 0; i < 10; i++ {
go func(j int, mucf *MuContainer) {
mucf.Lock()
mucf.data += j
mucf.Unlock()
}(i, mucglobal)
}
// B: Global only - working: adds 45
for i := 0; i < 10; i++ {
go func(j int) {
mucglobal.Lock()
mucglobal.data += j
mucglobal.Unlock()
}(i)
}
// C: Local declaration - working: adds 45
muclocal := &MuContainer{}
for i := 0; i < 10; i++ {
go func(j int, mucf *MuContainer) {
mucf.Lock()
mucf.data += j
mucf.Unlock()
}(i, muclocal)
}
// // D: Pointer to struct - not working: adds 0
// // I guess because it points directly to the struct.
// for i := 0; i < 10; i++ {
// go func(j int, mucf *MuContainer) {
// mucf.Lock()
// mucf.data += j
// mucf.Unlock()
// }(i, &MuContainer{})
// }
for {
mucglobal.RLock()
muclocal.RLock()
fmt.Printf("global: %d / local: %d\n", mucglobal.data, muclocal.data)
if mucglobal.data == 90 && muclocal.data == 45 {
muclocal.RUnlock()
mucglobal.RUnlock()
break
}
muclocal.RUnlock()
mucglobal.RUnlock()
}
}
答案1
得分: 3
D不起作用是因为你在每次迭代中创建了一个新的结构体。最终,你将拥有10个独立的MuContainer
实例。
前两个选项在语义上是相同的。对于这两个选项来说,每个goroutine共享同一个对象实例,该实例恰好是一个全局变量。
第二个选项与第一个选项类似,唯一的区别是被锁定和更新的对象恰好是一个局部变量。同样,这些goroutine都在同一个对象实例上工作。
因此,它们实际上并没有太大的区别,而且这三个选项都有各自的用途。
英文:
D is not working because you are creating a new struct for each iteration. In the end, you'll have 10 independent instances of MuContainer
.
The first two options are semantically identical. The bottom line for those two is that each goroutine shares the same instance of the object, which happens to be a global var.
The second one is similar with the only difference being the object locked and updated happens to be a local var. Again, the goroutines are working on the same instance of the object.
So these are not really different from each other, and all three have their uses.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论