go语言学习笔记——共享内存的处理

293 阅读1分钟

问题

先看一段代码

func TestCounter(t *testing.T) {
   counter := 0
   for i := 0; i < 1000; i++ {
      go func() {
         counter++
      }()
   }
   time.Sleep(time.Second * 1) // 增加时间等待,防止外部的协程比1000个协程先执行结束
   t.Logf("counter = %d", counter)
}

代码执行结果:

=== RUN   TestCounter
    share_mem_test.go:17: counter = 988
--- PASS: TestCounter (1.00s)
PASS

发现计数的结果,小于1000!!!

原因

这个是因为在1000个协程处理的时候,counter处于共享内存,导致并发写数据的时候异常。

解决办法——加锁

func TestCounterForSafe(t *testing.T) {
   var mut sync.Mutex
   counter := 0
   for i := 0; i < 1000; i++ {
      go func() {
         defer func() {
            mut.Unlock() // 解锁
         }()
         mut.Lock() // 加锁
         counter++
      }()
   }
   time.Sleep(time.Second * 1) // 增加时间等待,防止外部的协程比1000个协程先执行结束
   t.Logf("counter = %d", counter)
}

运行结果

=== RUN   TestCounterForSafe
    share_mem_test.go:33: counter = 1000
--- PASS: TestCounterForSafe (1.00s)
PASS

这个时候,发现数据对的上了。

但是有时候我们不知道代码要执行多久,没法准确估计出sleep时间。

优化

func TestCounterForWaitGroup(t *testing.T) {
   var wg sync.WaitGroup
   var mut sync.Mutex
   counter := 0
   for i := 0; i < 1000; i++ {
      wg.Add(1)
      go func() {
         defer func() {
            mut.Unlock() // 释放锁资源
         }()
         mut.Lock() // 加锁
         counter++
         wg.Done()
      }()
   }
   wg.Wait() //等到所有的任务执行结束
   t.Logf("counter = %d", counter)
}

运行结果

=== RUN   TestCounterForWaitGroup
    share_mem_test.go:52: counter = 1000
--- PASS: TestCounterForWaitGroup (0.00s)
PASS