3 回答
TA贡献1966条经验 获得超4个赞
当您的main()函数结束时,您的程序也会结束。它不会等待其他 goroutine 完成。
引用Go 语言规范:程序执行:
程序执行首先初始化主包,然后调用函数main。当该函数调用返回时,程序退出。它不会等待其他(非main)goroutine 完成。
有关更多详细信息,请参阅此答案。
你必须告诉你的main()函数等待SayHello()作为 goroutine 启动的函数完成。您可以将它们与频道同步,例如:
func SayHello(done chan int) {
for i := 0; i < 10; i++ {
fmt.Print(i, " ")
}
if done != nil {
done <- 0 // Signal that we're done
}
}
func main() {
SayHello(nil) // Passing nil: we don't want notification here
done := make(chan int)
go SayHello(done)
<-done // Wait until done signal arrives
}
另一种选择是通过关闭通道来表示完成:
func SayHello(done chan struct{}) {
for i := 0; i < 10; i++ {
fmt.Print(i, " ")
}
if done != nil {
close(done) // Signal that we're done
}
}
func main() {
SayHello(nil) // Passing nil: we don't want notification here
done := make(chan struct{})
go SayHello(done)
<-done // A receive from a closed channel returns the zero value immediately
}
笔记:
根据您的编辑/评论:如果您希望 2 个正在运行的SayHello()函数随机打印“混合”数字:您不能保证观察到这种行为。再次,有关更多详细信息,请参阅上述答案。在转到内存模型只能保证某些事件发生的其他事件之前,你有没有保证2个并发够程是如何执行的。
您可能会尝试使用它,但要知道结果不是确定性的。首先,您必须启用多个活动 goroutines 才能执行:
runtime.GOMAXPROCS(2)
其次,你必须首先SayHello()作为一个 goroutine启动,因为你当前的代码首先SayHello()在主 goroutine 中执行,只有在它完成后才会启动另一个:
runtime.GOMAXPROCS(2)
done := make(chan struct{})
go SayHello(done) // FIRST START goroutine
SayHello(nil) // And then call SayHello() in the main goroutine
<-done // Wait for completion
TA贡献1829条经验 获得超6个赞
或者(对于 icza 的回答)您可以使用WaitGroupfromsync包和匿名函数来避免更改原始SayHello.
package main
import (
"fmt"
"sync"
)
func SayHello() {
for i := 0; i < 10; i++ {
fmt.Print(i, " ")
}
}
func main() {
SayHello()
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
SayHello()
}()
wg.Wait()
}
为了同时打印数字,在单独的例程中运行每个打印语句,如下所示
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(fnScopeI int) {
defer wg.Done()
// next two strings are here just to show routines work simultaneously
amt := time.Duration(rand.Intn(250))
time.Sleep(time.Millisecond * amt)
fmt.Print(fnScopeI, " ")
}(i)
}
wg.Wait()
}
TA贡献1886条经验 获得超2个赞
当main函数返回时,Go 程序退出。
一种选择是使用类似的方法sync.WaitGroup来等待main从main.
另一种方法是调用runtime.Goexit()在main。从godoc:
Goexit 终止调用它的 goroutine。没有其他 goroutine 受到影响。Goexit 在终止 goroutine 之前运行所有延迟调用。因为 Goexit 不是一个恐慌,这些延迟函数中的任何恢复调用都将返回 nil。
从主协程调用 Goexit 会终止该协程,而不会返回 func main。由于 func main 没有返回,程序继续执行其他 goroutine。如果所有其他 goroutine 退出,程序就会崩溃。
这允许 main goroutine 停止执行,而后台例程继续执行。例如:
package main
import (
"fmt"
"runtime"
"time"
)
func f() {
for i := 0; ; i++ {
fmt.Println(i)
time.Sleep(10 * time.Millisecond)
}
}
func main() {
go f()
runtime.Goexit()
}
这比在 main 函数中永远阻塞更干净,尤其是对于无限的程序。一个缺点是,如果进程的所有 goroutine 都返回或退出(包括主 goroutine),Go 会将其检测为错误和恐慌:
fatal error: no goroutines (main called runtime.Goexit) - deadlock!
为了避免这种情况,至少一个 goroutine 必须os.Exit在它返回之前调用。调用os.Exit(0)立即终止程序并指示它没有错误地这样做。例如:
package main
import (
"fmt"
"os"
"runtime"
"time"
)
func f() {
for i := 0; i < 10; i++ {
fmt.Println(i)
time.Sleep(10 * time.Millisecond)
}
os.Exit(0)
}
func main() {
go f()
runtime.Goexit()
}
- 3 回答
- 0 关注
- 377 浏览
添加回答
举报