在 Golang 中使用互斥量或互斥量指针?
Use mutex or mutex pointer in Golang?
我有一个代码片段:
type calculation struct{
sum int
mutex sync.Mutex
}
func dosomething(c *calculation , wg *sync.WaitGroup) {
c.mutex.Lock()
c.sum++
c.mutex.Unlock()
wg.Done()
}
func main() {
t := time.Now()
c := new(calculation)
wg := new(sync.WaitGroup)
for i:=0; i<10000000; i++{
wg.Add(1)
go dosomething(c, wg)
}
wg.Wait()
fmt.Println(c.sum)
fmt.Println(time.Since(t))
}
但我发现使用互斥指针也可以:
type calculation struct{
sum int
mutex *sync.Mutex
}
func dosomething(c *calculation , wg *sync.WaitGroup) {
c.mutex.Lock()
c.sum++
c.mutex.Unlock()
wg.Done()
}
func main() {
t := time.Now()
c := &calculation{0, new(sync.Mutex)}
wg := new(sync.WaitGroup)
for i:=0; i<10000000; i++{
wg.Add(1)
go dosomething(c, wg)
}
wg.Wait()
fmt.Println(c.sum)
fmt.Println(time.Since(t))
}
我对这两个版本做了一些测试,发现经过的时间很接近。
那么我应该使用哪一个?为什么我应该使用互斥量或互斥量指针?它们有性能差异吗?
Go sync.Mutex
不能被复制,所以当你有一个可以被合理复制的数据结构但是有它自身的某些部分是共享的并且 不能 被合理地复制,并且您计划按值 and/or return 传递它,以便它被复制。
例如:
type Thingy struct {
notShared int
mtx *Sync.mutex
shared *int
}
func (t Thingy) Thingy {
t.notShared += 3
t.mtx.Lock()
*t.shared *= 2
t.mtx.Unlock()
return t
}
(可能更典型的是有多个非共享字段,然后一个指针指向一个包含互斥体本身和共享字段的struct
。上面主要是为了说明)
虽然您的 calculation
结构本身总是作为指针传递,但没有理由向您的示例添加间接级别。
编辑:您添加了有关性能差异的问题。添加一个额外的(否则不必要的)间接寻址通常会降低性能,但一般来说,您应该首先编写 最易读的 代码,然后测量它的性能问题。在我看来,添加一个额外的不必要的间接寻址往往会使代码的可读性稍差,因此在这里,性能和可读性是结合在一起的。
我有一个代码片段:
type calculation struct{
sum int
mutex sync.Mutex
}
func dosomething(c *calculation , wg *sync.WaitGroup) {
c.mutex.Lock()
c.sum++
c.mutex.Unlock()
wg.Done()
}
func main() {
t := time.Now()
c := new(calculation)
wg := new(sync.WaitGroup)
for i:=0; i<10000000; i++{
wg.Add(1)
go dosomething(c, wg)
}
wg.Wait()
fmt.Println(c.sum)
fmt.Println(time.Since(t))
}
但我发现使用互斥指针也可以:
type calculation struct{
sum int
mutex *sync.Mutex
}
func dosomething(c *calculation , wg *sync.WaitGroup) {
c.mutex.Lock()
c.sum++
c.mutex.Unlock()
wg.Done()
}
func main() {
t := time.Now()
c := &calculation{0, new(sync.Mutex)}
wg := new(sync.WaitGroup)
for i:=0; i<10000000; i++{
wg.Add(1)
go dosomething(c, wg)
}
wg.Wait()
fmt.Println(c.sum)
fmt.Println(time.Since(t))
}
我对这两个版本做了一些测试,发现经过的时间很接近。
那么我应该使用哪一个?为什么我应该使用互斥量或互斥量指针?它们有性能差异吗?
Go sync.Mutex
不能被复制,所以当你有一个可以被合理复制的数据结构但是有它自身的某些部分是共享的并且 不能 被合理地复制,并且您计划按值 and/or return 传递它,以便它被复制。
例如:
type Thingy struct {
notShared int
mtx *Sync.mutex
shared *int
}
func (t Thingy) Thingy {
t.notShared += 3
t.mtx.Lock()
*t.shared *= 2
t.mtx.Unlock()
return t
}
(可能更典型的是有多个非共享字段,然后一个指针指向一个包含互斥体本身和共享字段的struct
。上面主要是为了说明)
虽然您的 calculation
结构本身总是作为指针传递,但没有理由向您的示例添加间接级别。
编辑:您添加了有关性能差异的问题。添加一个额外的(否则不必要的)间接寻址通常会降低性能,但一般来说,您应该首先编写 最易读的 代码,然后测量它的性能问题。在我看来,添加一个额外的不必要的间接寻址往往会使代码的可读性稍差,因此在这里,性能和可读性是结合在一起的。