go语言学习笔记——只运行一次:once.DO

812 阅读1分钟

在多进程或者多协程场景中,如果想要保证代码只运行一次,防止出现并发问题,大多数的办法是通过加锁的形式,但是go语言有自带的函数: once.Do 进行解决

假设有个需求,变量num原始数值为1,是想把变量num进行一次累加操作,想要得到num的数值为2

样例

func TestCurren(t *testing.T) {
   num := 1
   var wg sync.WaitGroup
   for i := 0; i < 5; i++ {
      wg.Add(1)
      go func(n int) {
         num++ // 假设具体的业务逻辑
         wg.Done()
      }(num)
   }
   wg.Wait()
   t.Log("输出数据", num)
}

代码执行结果

=== RUN   TestCurren
    once_test.go:48: 输出数据 6
--- PASS: TestCurren (0.00s)
PASS

以上的逻辑,是分配了5个协程,但是在5个协程中,分别作了一次累加操作,所以最后的输出值是6,并非是2

使用once.Do进行改造

func TestCurren1(t *testing.T) {
   num := 1
   var wg sync.WaitGroup
   for i := 0; i < 5; i++ {
      wg.Add(1)
      go func(n int) {
         once.Do(func() {
            num++
         })
         wg.Done()
      }(num)
   }
   wg.Wait()
   t.Log("输出数据", num)
}

代码执行结果

=== RUN   TestCurren1
    once_test.go:64: 输出数据 2
--- PASS: TestCurren1 (0.00s)
PASS

在once.Do里,虽然5个协程都执行了,但是只会执行一次具体的逻辑,所以输出的结果是2。