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

huangapple go评论67阅读模式
英文:

What is the method set of `sync.WaitGroup`?

问题

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

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作为一个值而不是指针使用。但是sync包的页面指定了AddDoneWait函数需要一个*sync.WaitGroup

为什么/如何能够工作?

英文:

I have this simple program below

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()
	
}

Notice that I use var wg sync.WaitGroup as a value, not a pointer. But the page for the sync package specifies that the Add, Done and Wait function take a *sync.WaitGroup.

Why/How does this work?

答案1

得分: 9

sync.WaitGroupmethod set是空的方法集合:

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()
// 等等

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

这在规范: 调用中有说明:

> 如果x是可寻址的,并且&x的方法集包含m,那么x.m()(&x).m()的简写形式。

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

参考相关问题:

https://stackoverflow.com/questions/38481420/calling-a-method-with-a-pointer-receiver-by-an-object-instead-of-a-pointer-to-it/38481697#38481697

英文:

The method set of sync.WaitGroup is the empty method set:

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

Output (try it on the Go Playground):

0

This is because all the methods of sync.WaitGroup have pointer receivers, so they are all part of the method set of the *sync.WaitGroup type.

When you do:

var wg sync.WaitGroup

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

This is actually a shorthand for (&wg).Add(1), (&wg).Done() etc.

This is in Spec: Calls:

> If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m().

So when you have a value that is addressable (a variable is addressable), you may call any methods that have pointer receiver on non-pointer values, and the compiler will automatically take the address and use that as the receiver value.

See related question:

https://stackoverflow.com/questions/38481420/calling-a-method-with-a-pointer-receiver-by-an-object-instead-of-a-pointer-to-it/38481697#38481697

答案2

得分: 2

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

英文:

In your case you are modifying a global wg object, if you pass it to a function you have to use pointer because you need to modify the object itself. If you pass by value, inside your function you will be modifying a copy of it, not the object itself.

答案3

得分: 1

从文档中可以看到,WaitGroup用于等待一组goroutine完成。主goroutine调用Add方法设置要等待的goroutine数量。然后每个goroutine运行并在完成时调用Done方法。同时,可以使用Wait方法阻塞,直到所有goroutine都完成。

对于Add方法,它设置了要等待的goroutine数量。从你的代码中可以看出,你只有一个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(),它用于告诉一个goroutine已经完成工作,并让add减少1。你可以看到下面的代码,了解Done方法的工作原理:

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

最后,Wait方法用于阻塞goroutine,直到WaitGroup计数器为零。

还有一个问题:

为什么要使用WaitGroup?

从你的代码中可以看出,如果不使用WaitGroup,你将无法打印goroutine的结果。

总之,你可以在文档中阅读更多信息。

英文:

From the documentation WaitGroup :

> A WaitGroup waits for a collection of goroutines to finish. The main
> goroutine calls Add to set the number of goroutines to wait for. Then
> each of the goroutines runs and calls Done when finished. At the same
> time, Wait can be used to block until all goroutines have finished.

From your Question
> How does this work?

So for Add method is set the number of goroutine your called. From your code you have only one :

func main() {
    wg.Add(1)

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

    wg.Wait()

}

so it will tells goroutine to wait and print the result.
as for wg.Done() this is for telling the one gouroutine has finished to work. and it tells to the add to decrement to -1. You can see the code below How Done method works :

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

and finally for the Wait method this is for blocking goroutine until the WaitGroup counter is zero.

And another:

> Why ?

from your code above if you don't use WaitGroup you will not be able to print the result from the goroutine.

All in all you can read it in the documentation.

huangapple
  • 本文由 发表于 2017年2月27日 12:41:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/42477951.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定