霸王餐 (下)

未匹配的标注

先来看看这个不认识的 0x00c00006a068

我们把题目补充一些打印输出,

counter := 0 的下一行补充一句 fmt.Println("&counter", &counter)

补充后的代码如下:

package main

import (
    "fmt"
    "sync"
)

func main()  {
    counter := 0
    fmt.Println("&counter", &counter)
    wg := sync.WaitGroup{}
    for i := 0; i < 10000; i++{
        wg.Add(1)
        go func() {
            counter++
            wg.Done()
        }()
    }
    wg.Wait()
    fmt.Println(counter)
}

& 叫做取址符, 也就是获取内存地址的符号.

&counter 也就表示获取变量 counter 的内存地址.

然后我们运行起来看看:

go run -race main.go

输出如下:

&counter 0x00c00006a068
==================
WARNING: DATA RACE
Read at 0x00c00006a068 by goroutine 8:
  main.main.func1()
      E:/xiaobai/main.go:15 +0x3f

Previous write at 0x00c00006a068 by goroutine 7:
  main.main.func1()
      E:/xiaobai/main.go:15 +0x55

Goroutine 8 (running) created at:
  main.main()
      E:/xiaobai/main.go:14 +0x181

Goroutine 7 (finished) created at:
  main.main()
      E:/xiaobai/main.go:14 +0x181
==================
9998
Found 1 data race(s)
exit status 66

通过 &counter 对变量 counter 进行取址操作, 我们可以看到 0x00c00006a068 其实是变量 counter 的内存地址.

然后在 7 号协程和 8 号协程之间发生了竞争读取和写入, 以及发生竞争的代码行数信息等.

总而言之: 当很多协程并发执行共享同一内存地址时发生的竞争现象, 是一种常见的并发问题, 通常称之为 “竞态条件”.

也可以称之为 “非线程安全”, 当然在这里叫做 “非协程安全” 更合适.

在 Go 1.1 后提供了竞态条件检测器, 简单的使用方式就是在运行命令中添加 -race 参数指令.

新技能 Get, 那么以后有事没事都可以用竞态检测器检查一下我写的代码咯 —— 小白心想.

嘿嘿, 终于能吃上 “霸王餐” 了.

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
taadis
讨论数量: 0
发起讨论 只看当前版本


暂无话题~