golang sync.mutex
文章目录互斥锁读写锁互斥锁mutex的底层是通过atmoic原子操作来lock和unlocklock()和unlock()通过对资源枷锁解锁来避免争抢,同一时刻只能有一个goroutine对资源进行操作,等待的goroutine通过自旋和等待队列老获得锁读写锁当读的协程远远大于写的协程数,采用互斥锁不免影响性能,此时可采用读写锁有1000次的读和10次的写操作,在互斥锁的情况下的耗时1.4s将读的
文章目录
互斥锁
mutex的底层是通过atmoic原子操作来lock和unlock

lock()和unlock()通过对资源枷锁解锁来避免争抢,同一时刻只能有一个goroutine对资源进行操作,等待的goroutine通过自旋和等待队列老获得锁
读写锁
当读的协程远远大于写的协程数,采用互斥锁不免影响性能,此时可采用读写锁

有1000次的读和10次的写操作,在互斥锁的情况下的耗时1.4s
将读的锁换成读写锁

耗时是毫秒级的,以上很好的说明读多于写的场景,读写锁与互斥锁的性能差别
sync.Once()
Go语言中的sync包中提供了一个针对只执行一次场景的解决方案–sync.Once。
sync.Once只有一个Do方法,其签名如下:
func (o *Once) Do(f func()) {}
备注:如果要执行的函数f需要传递参数就需要搭配闭包来使用。只有一个Do()方法

场景 比如有一个函数从文件读取图片,保存在map里面,调用方调用时,先检查是否加载,没有加载的话先加载,再返回给调用方对应的图片,看起来没有问题,实际在并发的时候,可能同时有多个goroutine检测到还没有加载,就都去加载,这样就出现资源的浪费
sync.once内部包含bool值,记录sync.once是否被执行过
sync.map
Go语言的sync包中提供了一个开箱即用的并发安全版map–sync.Map。开箱即用表示不用像内置的map一样使用make函数初始化就能直接使用。同时sync.Map内置了诸如Store、Load、LoadOrStore、Delete、Range等操作方法。
Load(key interface{}) (value interface{}, ok bool)
//通过提供一个键key,查找对应的值value,如果不存在,则返回nil。ok的结果表示是否在map中找到值
Store(key, value interface{})
//这个相当于是写map(更新或新增),第一个参数是key,第二个参数是value
LoadOrStore(key, value interface{}) (actual interface{}, loaded bool)
//通过提供一个键key,查找对应的值value,如果存在返回键的现有值,否则存储并返回给定的值,如果是读取则返回true,如果是存储返回false
Delete(key interface{})
//通过提供一个键key,删除键对应的值
Range(f func(key, value interface{}) bool)
//循环读取map中的值。
//因为for ... range map是内置的语言特性,所以没有办法使用for range遍历sync.Map, 但是可以使用它的Range方法,通过回调的方式遍
eg:
package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Map
// 1. 写入
m.Store("qcrao", 18)
m.Store("stefno", 20)
// 2. 读取
age, _ := m.Load("qcrao")
fmt.Println(age.(int))
// 3. 遍历
m.Range(func(key, value interface{}) bool {
name := key.(string)
age := value.(int)
fmt.Println(name, age)
return true
})
// 4. 删除
m.Delete("qcrao")
age, ok := m.Load("qcrao")
fmt.Println(age, ok)
// 5. 读取或写入
m.LoadOrStore("stefno", 100)
age, _ = m.Load("stefno")
fmt.Println(age)
}

总结:
1 sync.map 是线程安全的,读取,插入,删除也都保持着常数级的时间复杂度。
2 通过读写分离,降低锁时间来提高效率,适用于读多写少的场景。
3 Range 操作需要提供一个函数,参数是 k,v,返回值是一个布尔值:ffunc(key, value interface{}) bool。
4 调用 Load 或 LoadOrStore 函数时,如果在 read 中没有找到 key,则会将 misses 值原子地增加 1,当 misses 增加到和 dirty 的长度相等时,会将 dirty 提升为 read。以期减少“读 miss”。
5新写入的 key 会保存到 dirty 中,如果这时 dirty 为nil,就会先新创建一个 dirty,并将 read 中未被删除的元素拷贝到 dirty。 当 dirty 为 nil 的时候,read 就代表 map 所有的数据;当 dirty 不为 nil 的时候,dirty 才代表 map 所有的数据。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)