[英]Prevent the main() function from terminating before goroutines finish in Golang
Have loook at this contrived example:看看这个人为的例子:
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++
}
}
The output of this program would be just "This will print".该程序的输出将只是“这将打印”。 Output of goroutines
printElo()
and printHello
will not be emitted because, I guess, the main()
function thread will finish before the goroutines have a chance to even start executing. goroutines
printElo()
和printHello
输出不会被发出,因为我猜main()
函数线程会在 goroutines 有机会开始执行之前完成。
What is the idiomatic way to make similar code work in Golang and not terminate prematurely?使类似代码在 Golang 中工作并且不会过早终止的惯用方法是什么?
Simplest, cleanest and "scalable" way to do it is to use a sync.WaitGroup
:最简单、最干净和“可扩展”的方法是使用
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()
}
Output (try it on the Go Playground ):输出(在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
Simple "rules" to follow when doing it with sync.WaitGroup
:使用
sync.WaitGroup
执行此操作时要遵循的简单“规则”:
WaitGroup.Add()
in the "original" goroutine (that starts a new) before the go
statementgo
语句之前在“原始”goroutine(启动一个新的)中调用WaitGroup.Add()
WaitGroup.Done()
deferred, so it gets called even if the goroutine panicsWaitGroup.Done()
,因此即使 goroutine WaitGroup.Done()
被调用WaitGroup
to other functions (and not use a package level variable), you must pass a pointer to it, else the WaitGroup
(which is a struct) would be copied, and the Done()
method called on the copy wouldn't be observed on the originalWaitGroup
传递给其他函数(而不是使用包级别变量),则必须传递指向它的指针,否则将复制WaitGroup
(结构体),并在副本上调用Done()
方法不会在原版上观察到As already mentioned sync.WaitGroup
is a right way in production code.如前所述,
sync.WaitGroup
是生产代码中的正确方法。 But when developing for test and debug purposes you can just add select{}
statement at the end or the main()
.但是在为测试和调试目的进行开发时,您可以在末尾或
main()
添加select{}
语句。
func main(){
go routine()
...
select{}
}
main()
then never returns and you would kill it with for example Ctrl-C
. main()
然后永远不会返回,你会用例如Ctrl-C
杀死它。 It isn't idiomatic, never used in production, but just very quick easy hack when developing.它不是惯用的,从未在生产中使用过,但只是在开发时非常快速容易破解。
You can use sync package and take a look at waitgroups
.您可以使用同步包并查看
waitgroups
。 You can take a look at a working Goplayground I set up.你可以看看我设置的一个有效的Goplayground。
Essentially本质上
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()
}
If you want just to play with results you can use "hack" with waiting for input:如果你只想玩结果,你可以使用“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')
}
If want to learn how to do synchronization read about sync package:如果想了解如何进行同步,请阅读有关同步包的信息:
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.