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 DS18B20内部ADC模数转换器
  • ¥15 做个有关计算的小程序
  • ¥15 MPI读取tif文件无法正常给各进程分配路径
  • ¥15 如何用MATLAB实现以下三个公式(有相互嵌套)
  • ¥30 关于#算法#的问题:运用EViews第九版本进行一系列计量经济学的时间数列数据回归分析预测问题 求各位帮我解答一下
  • ¥15 setInterval 页面闪烁,怎么解决
  • ¥15 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题
  • ¥15 如何用Python爬取各高校教师公开的教育和工作经历
  • ¥15 TLE9879QXA40 电机驱动