Go 并发之读写锁

2020-03-02  本文已影响0人  三梦哥

在业务当中我们常常需要遇到并发读写,其中读的频率远大于写的频率的情况,对数据的写入是需要互斥的,也就是同时只能允许一个线程去修改某个数据,但是允许多个读线程同时去读取某个数据。总的来说就是:

对比互斥锁和读写锁

当使用sync.Mutex 来实现并发同步

使用sync.Mutex来对读线程和写线程来进行互斥操作,代码如下:

package main

import (
    "fmt"
    "sync"
    "time"
)

var (
    wg   sync.WaitGroup
    lock sync.Mutex
    data int64
)

func read() {
    defer lock.Unlock()
    defer wg.Done()
    lock.Lock()
    time.Sleep(time.Millisecond) //模拟读取耗时
}

func write() {
    defer lock.Unlock()
    defer wg.Done()
    lock.Lock()
    data++
}

func main() {
    start := time.Now()
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go read()
    }
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go write()
    }
    wg.Wait()
    fmt.Println(data)
    d := time.Now().Sub(start)
    fmt.Println(d)
}

结果输出如下:

互斥锁
容易看出,耗时1.5s

当使用sync.RWMutex来实现并发同步

使用sync.RWMutex来对读线程和写线程来进行互斥操作,代码如下:

package main

import (
    "fmt"
    "sync"
    "time"
)

var (
    wg   sync.WaitGroup
    lock sync.RWMutex
    data int64
)

func read() {
    defer lock.RUnlock()
    defer wg.Done()
    lock.RLock()
    time.Sleep(time.Millisecond) //模拟读取耗时
}

func write() {
    defer lock.Unlock()
    defer wg.Done()
    lock.Lock()
    data++
}

func main() {
    start := time.Now()
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go read()
    }
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go write()
    }
    wg.Wait()
    fmt.Println(data)
    d := time.Now().Sub(start)
    fmt.Println(d)
}

结果输出如下:


读写锁

容易看出,耗时7ms

总结

方式 sync.Mutex sync.RWMutex
耗时 1.5s 7ms

所以在遇到并发读写,并且读的频率远大于写的频率的时候,需要使用sync.RWMutex读写锁来实现读写并发。

上一篇 下一篇

猜你喜欢

热点阅读