• Golang之并发资源竞争(读写锁)


    前面的有篇文章在讲资源竞争的时候,提到了互斥锁。互斥锁的根本就是当一个goroutine访问的时候,其他goroutine都不能访问,这样肯定保证了资源的同步,避免了竞争,不过也降低了性能。

    仔细剖析我们的场景,当我们读取一个数据的时候,如果这个数据永远不会被修改,那么其实是不存在资源竞争的问题的。因为数据是不变的,不管怎么读取,多少goroutine同时读取,都是可以的。

    所以其实读取并不是问题,问题主要是修改。修改的数据要同步,这样其他goroutine才可以感知到。所以真正的互斥应该是读取和修改、修改和修改之间,读取和读取是没有互斥操作的。

    所以这就延伸出来另外一种锁,叫做读写锁。

    读写锁可以让多个读操作同时并发,同时读取,但是对于写操作是完全互斥的。也就是说,当一个goroutine进行写操作的时候,其他goroutine既不能进行读操作,也不能进行写操作。

    package main
    
    import (
        "sync"
        "fmt"
        "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("读goroutine %d 正在读取...
    ",n)
        v := count
        fmt.Printf("读goroutine %d 读取结束,值为:%d
    ", n,v)
        wg.Done()
        rw.RUnlock()
    }
    
    func write(n int) {
        rw.Lock()
        fmt.Printf("写goroutine %d 正在写入...
    ",n)
        v := rand.Intn(1000)
        count = v
        fmt.Printf("写goroutine %d 写入结束,新值为:%d
    ", n,v)
        wg.Done()
        rw.Unlock()
    }

    我们在read里使用读锁,也就是RLock和RUnlock,写锁的方法名和我们平时使用的一样,是Lock和Unlock。这样,我们就使用了读写锁,可以并发地读,但是同时只能有一个写,并且写的时候不能进行读操作。现在我们再运行代码,可以从输出的数据看到,可以读到新值了。

    我们同时也可以使用go build -race检测,也没有竞争提示了。

  • 相关阅读:
    【自学php】第三天
    【自学php】第二天
    【自学php】第一天-macbook上配置php
    js数值转换
    js题
    【练习】响应式布局
    6.数据查询
    5.删除数据
    4.更新数据
    3.插入数据
  • 原文地址:https://www.cnblogs.com/liuzhongchao/p/9372289.html
Copyright © 2020-2023  润新知