waitGroup在并发访问下游的时候会被频发用到.

数据结构

type WaitGroup struct {
    noCopy noCopy

    // 64-bit value: high 32 bits are counter, low 32 bits are waiter count.
    // 64-bit atomic operations require 64-bit alignment, but 32-bit
    // compilers do not ensure it. So we allocate 12 bytes and then use
    // the aligned 8 bytes in them as state, and the other 4 as storage
    // for the sema.
    state1 [3]uint32
}

state1 字段第一个字节表示 all counter, 第二个字节表示 waiter count , 最后一个字节是 sema 的指针, 我们认作statep (根据前面的分析可以知道, sema使用avl + 链表的方式实现的).

实现上, state的最后一个指针 (称呼“statep”) 用来内部sema的地址, 挂载阻塞的goroutine. 第二个字节表示的waiter count, 当执行wait的时候, waitercount +1, 然后阻塞在statep上. 当执行Addd操作的时候,区分两种:

  1. 表示等待资源数量, 这个时候 delta > 0, 同时, waiter count = 0, 实现的时候只进行 all count +1
  2. 表示Done的语义, 这个时候 delta < 0, 同时, waiter count > 0, 因为 wg 的语义保障了 Wait 一定在 Done之前执行. 这个时候, all count - 1, 一直到 all count == 0的时候, 会触发唤醒.