sync.WaitGroup解析

当一个任务需要多个线程一起去完成时,主线程不能退出,主线程一旦退出,进程结束,所有的线程也被销毁了。如果可以用一个很粗糙的方式让主线程等待所有的工作线程都结束后在退出,参考代码:

package main

import "time"

func main() {
    for i := 1; i < 10; i++ {
        go func() {
            // do something...
        }()
    }

    time.Sleep(10 * time.Second)
}

通过估算,我们让主线程sleep10秒钟后退出,这是一种非常ugly的方式。Go语言提供了一个很优雅的方式来实现相同的功能。参考代码:

package main

import "sync"

func main() {
    var wg sync.WaitGroup
    wg.Add(10)
    for i := 1; i < 10; i++ {
        go func() {
            // do something...
            wg.Done()
        }()
    }
    wg.Wait()
}

还有一个稍微麻烦点的实现方式,使用Go的channel,参考代码:

package main

import "fmt"

func main() {
    done := make(chan bool)
    for i := 0; i < 10; i++ {
        go func(i int) {
            fmt.Println(i)
            done <- true
        }(i)
    }
    for i := 0; i < 10; i++ {
        <-done
    }
}

一个编程技巧,来自nsq的源代码:

package main

import (
    "fmt"
    "sync"
)

type WaitGroupWrapper struct {
    sync.WaitGroup
}

func (w *WaitGroupWrapper) Wrapper(cb func()) {
    w.Add(1)
    go func() {
        cb()
        w.Done()
    }()
    w.Wait()
}

type Person struct {
    Wrapper WaitGroupWrapper
    Name    string
    Age     int
}

func main() {
    var p Person
    exitFunc := func() {
        fmt.Println("exit func")
    }

    p.Wrapper.Wrapper(exitFunc)
    p.Wrapper.Wrapper(exitFunc)
}