一尘不染

防止main()函数在Golang中的goroutine完成之前终止

go

看一下这个人为的例子:

package main

import "fmt"

func printElo() {
    fmt.Printf("Elo\n")
}

func printHello() {
    fmt.Printf("Hello\n")
}

func main() {
    fmt.Printf("This will print.")
    i := 0
    for i < 10 {
        go printElo()
        go printHello()
        i++
    }
}

该程序的输出将仅为“ This will
print”。goroutine的输出printElo()并且printHello不会被发出,因为我想main()函数线程将在goroutines甚至有机会开始执行之前完成。

使类似的代码在Golang中工作并且不提前终止的惯用方式是什么?


阅读 755

收藏
2020-07-02

共1个答案

一尘不染

最简单,最干净和“可扩展”的方法是使用sync.WaitGroup

var wg = &sync.WaitGroup{}

func printElo() {
    defer wg.Done()
    fmt.Printf("Elo\n")
}

func printHello() {
    defer wg.Done()
    fmt.Printf("Hello\n")
}

func main() {
    fmt.Printf("This will print.")
    i := 0
    for i < 10 {
        wg.Add(1)
        go printElo()
        wg.Add(1)
        go printHello()
        i++
    }
    wg.Wait()
}

输出(在Go Playground上尝试):

This will print.Hello
Elo
Hello
Elo
Hello
Elo
Hello
Elo
Hello
Elo
Hello
Elo
Hello
Elo
Hello
Elo
Hello
Elo
Hello
Elo

执行以下操作时要遵循的简单“规则” sync.WaitGroup

  • WaitGroup.Add()go语句之前调用“原始” goroutine(开始一个新的)
  • 建议调用WaitGroup.Done()延迟,因此即使goroutine恐慌也可以调用
  • 如果要传递WaitGroup给其他函数(而不使用全局变量),则必须传递一个指向它的指针,否则WaitGroup将复制(它是一个结构),并且Done()在复制时将不会观察到该方法原本的
2020-07-02