阻止main()函数在Golang中的goroutines完成之前终止

阻止main()函数在Golang中的goroutines完成之前终止,go,concurrency,main,goroutine,Go,Concurrency,Main,Goroutine,让我们看看这个人为的例子: 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 p

让我们看看这个人为的例子:

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++
    }
}
主程序包
输入“fmt”
func printElo(){
格式打印F(“Elo\n”)
}
func printHello(){
fmt.Printf(“你好\n”)
}
func main(){
fmt.Printf(“这将打印”)
i:=0
对于i<10{
转到printElo()
去打印Hello()
我++
}
}
该程序的输出将仅为“this will print”。goroutines
printElo()
printHello
的输出将不会发出,因为我猜
main()
函数线程将在goroutines有机会开始执行之前完成

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

最简单、最干净和“可伸缩”的方法是使用:

使用
sync.WaitGroup
执行此操作时要遵循的简单“规则”:

  • 在语句之前调用“原始”goroutine(启动新的)
  • 建议调用deferred,这样即使goroutine恐慌也会调用它
  • 如果要将
    WaitGroup
    传递给其他函数(而不使用包级变量),则必须传递指向它的指针,否则将复制
    WaitGroup
    (它是一个结构),并且在副本上调用的
    Done()

如果您只想玩结果游戏,您可以使用“hack”等待输入:

package main

import (
    "fmt"
    "bufio"
    "os"
)

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++
    }

    reader := bufio.NewReader(os.Stdin)
    reader.ReadString('\n')
}
主程序包
进口(
“fmt”
“布菲奥”
“操作系统”
)
func printElo(){
格式打印F(“Elo\n”)
}
func printHello(){
fmt.Printf(“你好\n”)
}
func main(){
fmt.Printf(“这将打印”)
i:=0
对于i<10{
转到printElo()
去打印Hello()
我++
}
reader:=bufio.NewReader(os.Stdin)
reader.ReadString('\n')
}
如果要了解如何进行同步,请阅读关于同步包的内容:

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

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

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

func main() {

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

    wg.Wait()
}
主程序包
进口(
“fmt”
“同步”
)
var wg sync.WaitGroup
func printElo(){
格式打印F(“Elo\n”)
wg.Done()
}
func printHello(){
fmt.Printf(“你好\n”)
wg.Done()
}
func main(){
fmt.Printf(“这将打印”)
i:=0
对于i<10{
工作组.添加(2)
转到printElo()
去打印Hello()
我++
}
wg.Wait()
}
您可以使用并查看
waitgroups
。你可以看一看工作表

本质上

package main

import (
    "fmt"
    "sync"
    )

//Takes a reference to the wg and sleeps when work is done
func printElo(wg *sync.WaitGroup) {
    fmt.Printf("Elo\n")
    defer wg.Done()
}

//Takes a reference to the wg and sleeps when work is done
func printHello(wg *sync.WaitGroup) {
    fmt.Printf("Hello\n")
    defer wg.Done()
}

func main() {
    //Create a new WaitGroup
    var wg sync.WaitGroup
    fmt.Println("This will print.")

    for  i := 0; i < 10; i++ {
        //Add a new entry to the waitgroup
        wg.Add(1)
        //New Goroutine which takes a reference to the wg
        go printHello(&wg)
        //Add a new entry to the waitgroup
        wg.Add(1)
        //New Goroutine which takes a reference to the wg
        go printElo(&wg)
    }
    //Wait until everything is done
    wg.Wait()
}
主程序包
进口(
“fmt”
“同步”
)
//引用工作组并在工作完成时睡觉
func printElo(wg*sync.WaitGroup){
格式打印F(“Elo\n”)
推迟工作组完成()
}
//引用工作组并在工作完成时睡觉
func printHello(wg*sync.WaitGroup){
fmt.Printf(“你好\n”)
推迟工作组完成()
}
func main(){
//创建一个新的WaitGroup
var wg sync.WaitGroup
fmt.Println(“这将打印”)
对于i:=0;i<10;i++{
//将新条目添加到waitgroup
工作组.添加(1)
//引用工作组的新Goroutine
转到printHello(&wg)
//将新条目添加到waitgroup
工作组.添加(1)
//引用工作组的新Goroutine
转到printElo(&wg)
}
//等到一切都做完
wg.Wait()
}

如前所述,
sync.WaitGroup
是生产代码的正确方法。但是当出于测试和调试目的进行开发时,您可以在末尾添加
select{}
语句或
main()


main()。它不是惯用的,从来没有在生产中使用过,只是在开发时非常快速和简单的破解。

捕获了不同的方法。1.使用goroutines写入和main读取的通道,2。使用。还有一个供参考的方法。@algrebe,正如文章的评论员所指出的,作者本人所附议的-文章中描述的两种方法最初都是“危险的不准确”,因此它们不能真正构成这个问题的答案。您认为使用
var wg=&sync.WaitGroup{}是更好的方法吗
就像你做的那样,还是像我在代码片段中所做的那样将
wg
作为参考传递?如果是第一个,你能解释一下吗?对此我很好奇。@AndreaM16为了简单起见,我在这里使用了一个全局变量。如果代码/包的复杂性增加,或者您同时使用多个waitgroup,那么全局变量可能不可行,或者可能使事情变得更加复杂。请参阅编辑后的答案。感谢@icza也为sc2gears提供了帮助,在过去的日子里使用了很多。对不起,如果你离题了。看在上帝的份上,永远不要这样做。刚刚花了4天的时间调试一个使用了超过200%CPU的程序。“就是这样!”道兰戴罗为什么?
package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

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

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

func main() {

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

    wg.Wait()
}
package main

import (
    "fmt"
    "sync"
    )

//Takes a reference to the wg and sleeps when work is done
func printElo(wg *sync.WaitGroup) {
    fmt.Printf("Elo\n")
    defer wg.Done()
}

//Takes a reference to the wg and sleeps when work is done
func printHello(wg *sync.WaitGroup) {
    fmt.Printf("Hello\n")
    defer wg.Done()
}

func main() {
    //Create a new WaitGroup
    var wg sync.WaitGroup
    fmt.Println("This will print.")

    for  i := 0; i < 10; i++ {
        //Add a new entry to the waitgroup
        wg.Add(1)
        //New Goroutine which takes a reference to the wg
        go printHello(&wg)
        //Add a new entry to the waitgroup
        wg.Add(1)
        //New Goroutine which takes a reference to the wg
        go printElo(&wg)
    }
    //Wait until everything is done
    wg.Wait()
}
func main(){
    go routine()
    ...
    select{}
}