`sync.WaitGroup`的方法集是什么?

时间:2017-02-27 04:41:17

标签: go

我在下面有这个简单的程序

package main

import (
    "fmt"
    "sync"
    "time"
)

var wg sync.WaitGroup

func main() {
    wg.Add(1)

    go func() {
        fmt.Println("starting...")
        time.Sleep(1 * time.Second)
        fmt.Println("done....")
        wg.Done()
    } ()

    wg.Wait()

}

请注意,我使用var wg sync.WaitGroup作为值,而不是指针。但page for the sync package指定AddDoneWait函数采用*sync.WaitGroup

为什么/如何运作?

3 个答案:

答案 0 :(得分:3)

method setsync.WaitGroup是空方法集:

wg := sync.WaitGroup{}
fmt.Println(reflect.TypeOf(wg).NumMethod())

输出(在Go Playground上尝试):

0

这是因为sync.WaitGroup的所有方法都有指针接收器,所以它们都是*sync.WaitGroup类型方法集的一部分。

当你这样做时:

var wg sync.WaitGroup

wg.Add(1)
wg.Done()
// etc.

这实际上是(&wg).Add(1)(&wg).Done()等的简写。

这是Spec: Calls:

  

如果x可寻址且&x的方法集包含m,则x.m()(&x).m()的简写。

因此,当您有一个可寻址的值(变量是可寻址的)时,您可以调用任何在非指针值上具有指针接收器的方法,编译器将自动获取该地址并将其用作接收器值。

参见相关问题:

Calling a method with a pointer receiver by an object instead of a pointer to it?

答案 1 :(得分:1)

在您的情况下,您正在修改全局wg对象,如果将其传递给函数,则必须使用指针,因为您需要修改对象本身。如果你通过值传递,你将在函数内部修改它的副本,而不是对象本身。

答案 2 :(得分:1)

来自文档WaitGroup

  

WaitGroup等待完成goroutine的集合。主要的   goroutine调用Add来设置要等待的goroutines的数量。然后   每个goroutine运行并在完成后调用Done。在同一个   时间,等待可以用来阻止所有goroutines完成。

来自您的问题

  

这是如何运作的?

因此,Add方法设置了被调用的goroutine的数量。从你的代码中你只有一个:

func main() {
    wg.Add(1)

    go func() {
        fmt.Println("starting...")
        time.Sleep(1 * time.Second)
        fmt.Println("done....")
        wg.Done()
    } ()

    wg.Wait()

}

所以它会告诉goroutine等待并打印结果。 至于wg.Done(),这是为了告诉一个gouroutine已经完成工作。并告诉add递减到-1。您可以在Done方法的工作原理下看到以下代码:

// Done decrements the WaitGroup counter.
func (wg *WaitGroup) Done() {
    wg.Add(-1)
}

最后用于Wait方法,这是为了阻止goroutine,直到WaitGroup计数器为零。

另一个:

  

为什么?

如果您不使用WaitGroup,请在上面的代码

中输入goroutine中的结果。

总而言之,您可以在文档中阅读它。