[英]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.