go sync Once和sync.Map

405 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第23天,点击查看活动详情

sync Once

sync Once可以让代码只执行一次,即使是在高并发的情况下。

func main() {
   doOnce()
}
func doOnce() {
   var once sync.Once
   onceBody := func() {
      fmt.Println("Only once")
   }
   //用于等待协程执行完毕
   done := make(chan bool)
   for i := 0; i < 10; i++ {
      go func() {
         //把要执行的函数(方法)作为参数传给once.Do方法即可
         once.Do(onceBody)
         done <- true
      }()
   }
   for i := 0; i < 10; i++ {
      <-done
   }
}

image.png

上面示例中启动10个协程执行once.Do(onceBody),但是结果显而易见,onceBody只执行了一次。

sync Once适用于创建某个对象的单位,或者只加载一次的资源这种只执行一次的场景。

sync.Cond

sync.Cond在go语言sync包提供的同步原语中使用的并不是很频繁,它用于发出信号(一对一)或广播信号(一对多)到goroutine,它具有阻塞协程和唤醒协程的功能。

sync.Cond有三个方法:

方法解释
Wait阻塞当前协程
Signal唤醒一个等待时间最长的协程
Broadcast唤醒所有等待的协程

sync.Map

sync.Map是并发版本的go语言的Map,sync.Map有一些方法:

方法解释
Store存储一对key-value值
Load根据key获取对应的value值,可以判断key是否存在
LoadOrStore如果key对应的value存在,则返回该value,如果不存在,存储value
Delete伤处一个key-value键值对
Range循环迭代sync.Map,效果与for range一样
func main() {
   m := &sync.Map{}
   // 添加元素
   m.Store(1, "one")
   m.Store(2, "two")
   // 获取元素1
   value, contains := m.Load(1)
   if contains {
      fmt.Printf("%s\n", value.(string))
   }
   // 返回已存value,否则把指定的键值存储到map中
   value, loaded := m.LoadOrStore(3, "three")
   if !loaded {
      fmt.Printf("%s\n", value.(string))
   }
   m.Delete(3)
   // 迭代所有元素
   m.Range(func(key, value interface{}) bool {
      fmt.Printf("%d: %s\n", key.(int), value.(string))
      return true
   })
}