美文网首页
Go语言锁的使用

Go语言锁的使用

作者: 码客南君 | 来源:发表于2020-07-23 09:14 被阅读0次

    Golang 中的锁是用来解决并发中资源同步的问题。当多个任务同时访问一个资源进行读写操作,会造成对结果的不确定。

    互斥锁

    互斥锁的本质就是当一个资源被 goroutine 访问的时候,其它的 goroutine 就不能访问这个资源。这样避免了多个协程去争夺一个资源的情况出现。不好的地方就是简洁粗暴,降低了一点效率。

    对互斥锁有获取锁和释放锁两种操作。

    代码示例

    package main
    
    import (
      "fmt"
      "sync"
      "time"
    )
    
    func main(){
        //声明
        var mutex sync.Mutex
    
        for i := 1; i < 10; i++ {
          go func(i int) {
          fmt.Printf("准备上锁 (互斥锁%d)\n", i)
          mutex.Lock()
          fmt.Printf("已上锁 (互斥锁%d)\n", i)
          }(i)
        }
    
        time.Sleep(5 * time.Second)
        fmt.Println("准备解锁")
    
        //解锁
        mutex.Unlock()
        fmt.Println("互斥锁已解开")
        time.Sleep(5 * time.Second)
    }
    

    运行程序

    准备上锁 (互斥锁1)
    已上锁 (互斥锁1)
    准备上锁 (互斥锁2)
    准备上锁 (互斥锁7)
    准备上锁 (互斥锁9)
    准备上锁 (互斥锁5)
    准备上锁 (互斥锁6)
    准备上锁 (互斥锁4)
    准备上锁 (互斥锁8)
    准备上锁 (互斥锁3)
    准备解锁
    互斥锁已解开
    已上锁 (互斥锁2)
    

    读写锁

    读写锁把goroutine竞争资源的场景细分了,实现的更巧妙些。

    有些场景下,我们读取一个数据,并没有修改的需求。这样就算多个 goroutine 一起去读取数据,也不会存在资源竞争的问题。

    关键在写数据上。资源竞争发生在 1. 数据读取和修改 2.数据修改和修改这两种情况下。

    读写锁可以让多个 goroutine 同时并发读取,而对写操作的实现和互斥锁一样。一个 goroutine 写完,另一个 goroutine 才可以读取,更改。

    这样效率就比互斥锁提高了。

    代码示例

    package main
    
    import (
      "fmt"
      "sync"
      "math/rand"
    )
    
    var count int
    // 等待组 解决同步阻塞等待
    var wg sync.WaitGroup
    // 声明读写锁
    var rw sync.RWMutex
    
    func main(){
        wg.Add(10)
        for i:=0;i<5;i++ {
          go read(i)
        }
        for i:=0;i<5;i++ {
          go write(i);
        }
        wg.Wait()
    }
    
    func read(n int) {
        rw.RLock()
        fmt.Printf("读协程%d 正在读取\n",n)
        v := count
        fmt.Printf("读协程%d 读取结束 %d\n", n,v)
        wg.Done()
        rw.RUnlock()
    }
    
    func write(n int) {
        rw.Lock()
        fmt.Printf("写协程%d 正在写入\n",n)
        v := rand.Intn(100)
        count = v
        fmt.Printf("写协程%d 写入结束 %d\n", n,v)
        wg.Done()
        rw.Unlock()
    }
    

    运行程序

    读协程3 正在读取
    读协程3 读取结束 0
    写协程4 正在写入
    写协程4 写入结束 81
    读协程4 正在读取
    读协程4 读取结束 81
    读协程1 正在读取
    读协程1 读取结束 81
    读协程0 正在读取
    读协程0 读取结束 81
    读协程2 正在读取
    读协程2 读取结束 81
    写协程0 正在写入
    写协程0 写入结束 87
    写协程1 正在写入
    写协程1 写入结束 47
    写协程2 正在写入
    写协程2 写入结束 59
    写协程3 正在写入
    写协程3 写入结束 81
    

    在读取操作里用到了读锁:RLock 和 RUnlock。读写锁可以并发的读,但只能一个一个写,写的时候不能进行读操作。

    相关文章

      网友评论

          本文标题:Go语言锁的使用

          本文链接:https://www.haomeiwen.com/subject/hlrclktx.html