让我们看看这个精心设计的例子:

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".Goroutines printElo()printHello的输出将不会发出,因为我猜main()函数线程将在Goroutines甚至有机会开始执行之前完成.

让类似的代码在Golang中工作而不过早终止的惯用方法是什么?

推荐答案

要做到这一点,最简单、最干净且"可伸缩"的方法是使用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时要遵循的简单"规则":

  • go语句之前,在"原始"goroutine(开始一个新的)中调用WaitGroup.Add()
  • 建议推迟拨打WaitGroup.Done(),因此即使goroutinepanic 也会拨打
  • 如果要将WaitGroup传递给其他函数(而不使用包级别变量),必须传递指向它的指针,否则WaitGroup( struct )将被复制,并且在副本上调用的Done()方法在原始函数上不会被观察到

Go相关问答推荐

如何使用Promela建模语言对Golang RWLock进行建模

CGO Linux到Windows交叉编译中的未知类型名称

Golang应用程序:所请求的资源上不存在HTTP-Control-Allow-Origin标头

Websocket服务器实现与x/net库trowing 403

无法在32位计算机上运行Golang应用程序

如何用';贪婪原则';正确地

Kusto Go API 从多个表查询

「GORM错误」不支持的数据类型:&[],不正确的模式

如何从 Go Lambda 函数返回 HTML?

使用 httptest 对 http 请求进行单元测试重试

Github Actions Go lambda 项目不同的 sha256sums

Go 信号处理程序不处理终端窗口关闭

从数据库中带有 imageurl 的文件夹中获取图像,并在我的浏览器中用 golang 中的 echo 显示

如何模仿联合类型

fmt.Printf() 标志 '0' 不会被字符串忽略

GRPC 元数据未在 Go 中更新

如何在 GORM 中获取字段值

在 Golang 中获取谷歌云服务帐户的访问令牌?

如何将类型转换为字节数组golang

Golang 查询扫描未将查询正确扫描到 struct 中