华域联盟 Golang Go 互斥锁和读写互斥锁的实现

Go 互斥锁和读写互斥锁的实现

文章目录[隐藏]

目录

先来看这样一段代码,所存在的问题:

var wg sync.WaitGroup
var x int64

func main() {
 wg.Add(2)
 go f()
 go f()
 wg.Wait()
 fmt.Println(x) // 输出:12135
}

func f()  {
 for i:=0;i<10000;i++ {
  x = x+1
 }
 wg.Done() 
}

这里为什么输出是 12135(不同的机器结果不一样),而不是20000。

因为 x 的赋值,总共分为三个步骤:取出x的值、计算x的结果、给x赋值。那么由于对于f函数的调用采用了goroutine协程,所以存在资源竞争的问题,所以有赋值和计算过程中存在脏数据。对于此类的问题,可以采用互斥锁解决:

互斥锁

互斥锁是一种常用的控制共享资源访问的方法,它能够保证同时只有一个goroutine可以访问共享资源。Go语言中使用sync包的Mutex类型来实现互斥锁。

var wg sync.WaitGroup
var x int64
var lock sync.Mutex

func main() {
 wg.Add(2)
 go f()
 go f()
 wg.Wait()
 fmt.Println(x) // 输出:20000
}

func f()  {
 for i:=0;i<10000;i++ {
  lock.Lock() // 加互斥锁
  x = x+1
  lock.Unlock() // 解锁
 }
 wg.Done() 
}

使用互斥锁能够保证同一时间有且只有一个goroutine进入临界区,其他的goroutine则在等待锁;当互斥锁释放后,等待的goroutine才可以获取锁进入临界区,多个goroutine同时等待一个锁时,唤醒的策略是随机的。

读写互斥锁

互斥锁是完全互斥的,但是有很多实际的场景下是读多写少的,当我们并发的去读取一个资源不涉及资源修改的时候是没有必要加锁的,这种场景下使用读写锁是更好的一种选择。读写锁在Go语言中使用sync包中的RWMutex类型。

读写锁分为两种:读锁和写锁。当一个goroutine获取读锁之后,其他的goroutine如果是获取读锁会继续获得锁,如果是获取写锁就会等待;当一个goroutine获取写锁之后,其他的goroutine无论是获取读锁还是写锁都会等待。

var (
 x1 int64
 wg1 sync.WaitGroup
 lock1 sync.Mutex
 rwlock sync.RWMutex
)

func main() {
 startTime := time.Now()
 for i:=0;i<100;i++ {
  wg1.Add(1)
  write()
 }
 for i:=0;i<10000;i++ {
  wg1.Add(1)
  read()
 }
 wg1.Wait()
 fmt.Println(time.Now().Sub(startTime))

 // 互斥锁用时: 973.9304ms
 // 读写互斥锁用时: 718.094ms
}

func read()  {
 defer wg1.Done()
 //lock1.Lock() // 互斥锁
 rwlock.RLock() // 读写互斥锁
 fmt.Println(x1)
 //lock1.Unlock() // 互斥锁
 rwlock.RUnlock() // 读写互斥锁
}

func write()  {
 defer wg1.Done()
 lock1.Lock()
 x1 = x1+1
 lock1.Unlock()
}

到此这篇关于Go 互斥锁和读写互斥锁的实现的文章就介绍到这了,更多相关Go 互斥锁和读写互斥锁内容请搜索华域联盟以前的文章或继续浏览下面的相关文章希望大家以后多多支持华域联盟!

本文由 华域联盟 原创撰写:华域联盟 » Go 互斥锁和读写互斥锁的实现

转载请保留出处和原文链接:https://www.cnhackhy.com/111554.htm

本文来自网络,不代表华域联盟立场,转载请注明出处。

作者: sterben

go语言区块链实战实现简单的区块与区块链

发表回复

联系我们

联系我们

2551209778

在线咨询: QQ交谈

邮箱: [email protected]

工作时间:周一至周五,9:00-17:30,节假日休息

关注微信
微信扫一扫关注我们

微信扫一扫关注我们