SayHello()
按预期执行时,goroutine不打印任何内容。 package main
import "fmt"
func SayHello() {
for i := 0; i < 10 ; i++ {
fmt.Print(i, " ")
}
}
func main() {
SayHello()
go SayHello()
}
#1 楼
当main()
函数结束时,程序也将结束。它不等待其他goroutine完成。从Go语言规范中引用:程序执行:
程序执行从初始化主程序包开始,然后调用功能
main
。当该函数调用返回时,程序退出。它不等待其他(非main
)例程完成。有关更多详细信息,请参见此答案。等待作为goroutine启动的
main()
函数完成。您可以将它们与通道同步,例如: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
}
另一种选择是通过关闭通道来表示完成信号: >
注释:
根据您的编辑/注释:如果要让2个正在运行的
SayHello()
函数随机打印“混合”数字:您不能保证观察到这种行为。同样,请参阅上述答案以获取更多详细信息。 Go Memory Model仅保证某些事件先于其他事件发生,而不能保证如何执行2个并发goroutine。您可以尝试使用它,但是知道结果不会是确定的。首先,您必须启用多个活动goroutine才能执行:主goroutine,只有完成后才启动另一个goroutine:
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
}
评论
是的,我在阅读dave.cheney.net/2014/03/19/channel-axioms后才了解您的编辑:A永远发送到nil通道块,A永远接收nil通道块。
–VonC
2015年3月10日在7:40
@DineshPanchananam您所说的“无序”时尚是什么意思?您希望从运行的2个SayHello()函数中随机看到混合数吗?
–icza
15年3月10日在8:03
@DineshPanchananam我编辑了我的答案以解决这种情况。简而言之,您不能保证观察到这种行为(即使您这样做,也不是确定性的)。
–icza
2015年3月10日在8:28
#2 楼
另一种方法(以icza的回答),您可以使用WaitGroup
软件包中的sync
和匿名函数来避免更改原始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()
}
评论
@DineshPanchananam是否要在单独的例程中打印每个数字?
– Sundrique
2015年3月10日在8:05
不,我期望有“平行”的意思,但是我认为我错了。
–Dinesh Panchananam
2015年3月10日在8:10
@DineshPanchananam检查答案的第二部分
– Sundrique
2015年3月10日在8:21
另外,在只有一个函数调用时(第一个代码示例),请不要使用defer-在函数调用之后将wg.Done()移至即可。在这种情况下,无需使用延迟。
– ttacon
2015年3月10日14:14
#3 楼
当main
函数返回时,Go程序退出。在godoc中:Goexit终止调用它的goroutine。没有其他goroutine受到影响。 Goexit在终止goroutine之前运行所有延迟的调用。由于Goexit不会发生紧急情况,因此这些延迟函数中的任何恢复调用都将返回nil。
从主goroutine调用Goexit将终止该goroutine,而不会返回func main。由于func main尚未返回,因此程序将继续执行其他goroutine。如果所有其他goroutine都退出,则程序将崩溃。
这允许主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()
}
这比永久阻塞主函数更干净,尤其是对于无限程序。缺点是,如果某个进程的所有goroutine都返回或退出(包括主goroutine),则Go会将其检测为错误并感到恐慌:在返回之前,请致电
sync.WaitGroup
。调用main
立即终止程序,并指示它这样做没有错误。例如:fatal error: no goroutines (main called runtime.Goexit) - deadlock!
评论
如果时间不执行,可能不会执行Goroutine的重复。包括睡眠