dongyou4411 2018-12-15 10:48
浏览 129
已采纳

多个sync.WaitGroup的用法

I have seen a few different examples of sync.WaitGroup

Example 1

var wg sync.WaitGroup

wg.Add(1)
go doStuff(&wg)
wg.Wait()

Example 2

wg := new(sync.WaitGroup)

wg.Add(1)
go doStuff(wg)
wg.Wait()

the difference is really in the way sync.WaitGroup is initialized var vs new

if using the var option it has to be passed as a pointer &wg to the goroutine but if I use the new option I can send it as wg

What is the difference between the two examples? Which of these 2 above is correct? Is one preferred over the other in certain situations?

I am writing a program which creates multiple sync.WaitGroups so does it matter if new or var is used?

  • 写回答

1条回答 默认 最新

  • 普通网友 2018-12-15 11:39
    关注

    Both of your examples work properly. Also note that instead of new(), you could also use a composite literal and take its address like this:

    var wg = &sync.WaitGroup{}
    

    Methods of sync.WaitGroup have pointer receiver, so whenever you call its methods, the address of the WaitGroup struct value is needed. This is not a problem, as when wg is a non-pointer, the wg.Add(1) and wg.Done() calls are shorthand for (&wg).Add(1) and (&wg).Done(), so the compiler automatically "rewrites" those calls to take the address of wg first, and use that address as the receiver of the methods.

    However, I still think that if a value is only useful as a pointer (sync.WaitGroup is a shining example), you should declare it and work with it as a pointer in the first place, so that leaves less room for errors.

    For example, if you use a non-pointer and you declare the function to expect a non-pointer, and you pass it as a non-pointer, you will get no compile-time error, yet it will misbehave (sync.WaitGroup should not be copied).

    Although today's linter would give you a warning message, still, I believe it's best to work with pointers all the time.

    Another reason to work with pointers: if a function would return a sync.WaitGroup, or if you have a map that stores sync.WaitGroup as values, you would not be able to call methods on the result, because return values of functions and map index operations are not addressable. If the function would return a pointer value, or if you would store pointers in the map in the first place, you could still call the methods without having to store them in a local variable. For details, see How can I store reference to the result of an operation in Go?

    For example:

    func getWg() sync.WaitGroup { return sync.WaitGroup{} }
    
    getWg().Wait() // Compile-time error!
    
    m := map[int]sync.WaitGroup{
        1: sync.WaitGroup{},
    }
    
    m[1].Wait() // Again: compile-time error
    

    But these work:

    func getWg() *sync.WaitGroup { return &sync.WaitGroup{} }
    
    getWg().Wait() // Works, you can call methods on the return value
    
    m := map[int]*sync.WaitGroup{
        1: &sync.WaitGroup{},
    }
    
    m[1].Wait() // Also works
    

    Read more about this here: Why should constructor of Go return address?

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥15 c++头文件不能识别CDialog