Go 互斥锁和读写互斥锁的实现
作者:李斌的BLOG 发布时间:2024-04-25 15:00:41
标签: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()
}
来源:https://juejin.cn/post/7025086608777052196
0
投稿
猜你喜欢
- return 语句就是讲结果返回到调用的地方,并把程序的控制权一起返回程序运行到所遇到的第一个return即返回(退出def块),不会再运行
- 本文实例讲述了Python整型运算之布尔型、标准整型、长整型操作。分享给大家供大家参考,具体如下:#coding=utf8def integ
- new fun的执行过程分析,学习面向对象的朋友可以参考下。(1)创建一个新的对象,并让this指针指向它;(2)将函数的prototype
- 刚刚心血来潮,编了一个国际域名查询的功能页面,比较简单,没有做什么美化和修饰,主要利用了服务器端的XMLHTTP访问第三方服务器实现域名查询
- 首先,我想说一下Javascript的装载和执行。通常来说,浏览器对于Javascript的运行有两大特性:1)载入后马上执行,2)执行时会
- python中有的df列比较长head的时候会出现省略号,现在数据分析常用的就是基于anaconda的notebook和sypder,在sp
- 一、基本形式sorted(iterable[, cmp[, key[, reverse]]])iterable.sort(cmp[, key
- pyserial模块封装了对串口的访问,兼容各种平台。安装pip insatll pyserial初始化简单初始化示例import seri
- 本文实例讲述了Python实现查找数组中任意第k大的数字算法。分享给大家供大家参考,具体如下:模仿partion方法,当high=low小于
- 前言玩博客一个多月了,渐渐发现了一些有意思的事,经常会有人用同样的评论到处刷,不知道是为了加没什么用的积分,还是纯粹为了表达楼主好人。那么问
- python使用ctypes模块调用windows api GetVersionEx获取当前系统版本,没有使用python32#!c:/py
- 通常我们在制作上图的时候,会分别给四个div加上不同的css属性,来实现中间间隔。但我们更希望的是不需要对html标签做标识,直接能通过cs
- 一、%号占位符这是一种引入最早的一种,也是比较容易理解的一种方式.使用方式为:1、格式化字符串中变化的部分使用占位符2、变量以元组形式提供3
- 一、介绍ADB(Android调试桥)是一个命令行工具(CLI),可用于控制Android设备并与之通信。您可以执行许多操作,例如安装应用程
- 在做task中,需要将TXT文本中的某一项注释修改,但是python对txt文本只有写入和读取两种操作。我采用的方法是:1.读取txt文件,
- 调用opencv库,将yuv图像转为jpg图像。代码如下:# define _CRT_SECURE_NO_WARNINGS#include
- 本文实例讲述了Go语言通过Luhn算法验证信用卡卡号是否有效的方法。分享给大家供大家参考。具体实现方法如下:package mainimpo
- 前言刚刚看了EuroPython 2017一篇演讲,Why You Don't Need Design Patterns in Py
- 乱码问题破解压缩包时候会存在中文乱码问题!1:直接使用Everything搜索出要修改的库文件 zipfile.py ,并用notepad+
- 前言MySQL 服务器正确安装以后,可以通过命令行管理工具或者图形化的管理工具来操作 MySQL 数据库。MySQL 图形化管理工具极大地方