簡體   English   中英

防止 main() 函數在 Golang 中的 goroutines 完成之前終止

[英]Prevent the main() function from terminating before goroutines finish in Golang

看看這個人為的例子:

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

該程序的輸出將只是“這將打印”。 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() ,因此即使 goroutine WaitGroup.Done()被調用
  • 如果要將WaitGroup傳遞給其他函數(而不是使用包級別變量),則必須傳遞指向它的指針,否則將復制WaitGroup (結構體),並在副本上調用Done()方法不會在原版上觀察到

如前所述, sync.WaitGroup是生產代碼中的正確方法。 但是在為測試和調試目的進行開發時,您可以在末尾或main()添加select{}語句。

func main(){
    go routine()
    ...
    select{}
}

main()然后永遠不會返回,你會用例如Ctrl-C殺死它。 它不是慣用的,從未在生產中使用過,但只是在開發時非常快速容易破解。

您可以使用同步包並查看waitgroups 你可以看看我設置的一個有效的Goplayground。

本質上

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()
}

如果你只想玩結果,你可以使用“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')
}

如果想了解如何進行同步,請閱讀有關同步包的信息:

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()
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM