Go 停止goroutines

示例

package main

import (
    "log"
    "sync"
    "time"
)

func main() {
    // WaitGroup让主goroutine等待所有其他goroutine
    //终止。但是,这在Go中并不隐含。WaitGroup必须
    // 在执行任何goroutine之前显式地增加 
    // (即在`go`关键字之前),并且必须通过调用将其递减
    // wg.Done()在每个goroutine的结尾(通常通过`defer`关键字)。 
    wg := sync.WaitGroup{}

    // 停止通道是一个无缓冲通道,当主通道关闭时
    // 线程希望所有其他goroutine终止(无法执行 
    //中断Go中的另一个goroutine)。每个goroutine必须多路复用其
    // 与停止频道一起工作,以确保生气勃勃。
    stopCh := make(chan struct{})


    for i := 0; i < 5; i++ {
        // 在开始之前,增加WaitGroup是很重要的
        // goroutine(而不是在goroutine中),因为调度程序
        // 不保证goroutine在开始之前开始执行 
        // 主goroutine调用wg.Wait()。
        wg.Add(1)
        go func(i int, stopCh <-chan struct{}) {
            // 关键字defer保证WaitGroup计数为 
            // 当goroutine退出时递减。
            defer wg.Done()

            log.Printf("started goroutine %d", i)

            select {
            // 由于我们从未在该通道上发送空结构,因此我们可以 
            // 用通道上的接收返回来表示
            // 通道已关闭(记得接收永不阻塞
            // 封闭频道)。   
            case <-stopCh:
                log.Printf("stopped goroutine %d", i)
            }
        }(i, stopCh)
    }

    time.Sleep(time.Second * 5)
    close(stopCh)
    log.Printf("stopping goroutines")
    wg.Wait()
    log.Printf("all goroutines stopped")
}