在 Golang 中使用互斥锁还是互斥锁指针?

Art*_*san 0 pointers mutex go

我有一个代码片段:

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))
}
Run Code Online (Sandbox Code Playgroud)

但我发现使用互斥指针也有效:

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))
}
Run Code Online (Sandbox Code Playgroud)

我对这两个版本进行了一些测试,发现经过的时间很接近。

那么我应该使用哪一种呢?为什么我应该使用互斥或​​互斥指针?它们有性能差异吗?

tor*_*rek 6

Gosync.Mutex不能被复制,所以sync.Mutex当你有一个数据结构可以被合理地复制但它有一部分是共享的并且不能被合理地复制时,你将使用指向(共享的,非复制的)的指针,并且你计划按值传递它和/或返回它,以便它被复制。

例如:

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
}
Run Code Online (Sandbox Code Playgroud)

(可能更典型的是有多个非共享字段,然后一个指向struct包含互斥体本身和共享字段的a 的指针。以上主要用于说明)

鉴于您的 calculation结构本身总是作为指针传递,因此没有理由在您的示例中添加间接级别。

编辑:您添加了有关性能差异的问题。添加额外的(否则不必要的)间接通常会降低性能,但一般来说,您应该首先编写最易读的代码,然后针对性能问题对其进行衡量。在我看来,添加额外的不必要的间接会使代码可读性稍差,所以在这里,性能和可读性是相辅相成的。