我在下面有这个简单的程序
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指定Add
,Done
和Wait
函数采用*sync.WaitGroup
。
为什么/如何运作?
答案 0 :(得分:3)
method set的sync.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()
等的简写。
如果
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中的结果。
总而言之,您可以在文档中阅读它。