goroutine 没有输出
No output from goroutine
虽然 SayHello()
按预期执行,但 goroutine 不打印任何内容。
package main
import "fmt"
func SayHello() {
for i := 0; i < 10 ; i++ {
fmt.Print(i, " ")
}
}
func main() {
SayHello()
go SayHello()
}
当您的 main()
函数结束时,您的程序也会结束。它不会等待其他 goroutines 完成。
引自Go Language Specification: Program Execution:
Program execution begins by initializing the main package and then invoking the function main
. When that function invocation returns, the program exits. It does not wait for other (non-main
) goroutines to complete.
有关详细信息,请参阅 。
你必须告诉你的 main()
函数等待作为 goroutine 启动的 SayHello()
函数完成。您可以将它们与频道同步,例如:
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
}
备注:
根据您的 edits/comments:如果您希望 2 运行 SayHello()
函数随机打印 "mixed" 数字:您无法保证观察到此类行为。同样, for more details. The Go Memory Model 只保证某些事件发生在其他事件之前,你不能保证 2 个并发 goroutines 是如何执行的。
您可以尝试一下,但要知道结果不是确定性的。首先,您必须启用多个活动的 goroutines 以执行:
runtime.GOMAXPROCS(2)
其次,您必须首先将 SayHello()
作为 goroutine 启动,因为您当前的代码首先在主 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
或者(对于 icza 的回答)你可以使用 sync
包中的 WaitGroup
和匿名函数来避免改变原始 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()
}
Go 程序在 main
函数 returns.
时退出
一个选择是使用 sync.WaitGroup
之类的东西来等待 main
在 return 从 main
之前生成的其他 goroutines。
另一种选择是在 main
中调用 runtime.Goexit()
。来自 godoc:
Goexit terminates the goroutine that calls it. No other goroutine is affected. Goexit runs all deferred calls before terminating the goroutine. Because Goexit is not a panic, any recover calls in those deferred functions will return nil.
Calling Goexit from the main goroutine terminates that goroutine without func main returning. Since func main has not returned, the program continues execution of other goroutines. If all other goroutines exit, the program crashes.
这允许主 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 函数中永远阻塞要干净,尤其是对于无限的程序。一个缺点是,如果一个进程的所有 goroutines return 或退出(包括主 goroutine),Go 将检测到这是一个错误和恐慌:
fatal error: no goroutines (main called runtime.Goexit) - deadlock!
为避免这种情况,至少有一个 goroutine 必须在 return 之前调用 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()
}
虽然 SayHello()
按预期执行,但 goroutine 不打印任何内容。
package main
import "fmt"
func SayHello() {
for i := 0; i < 10 ; i++ {
fmt.Print(i, " ")
}
}
func main() {
SayHello()
go SayHello()
}
当您的 main()
函数结束时,您的程序也会结束。它不会等待其他 goroutines 完成。
引自Go Language Specification: Program Execution:
Program execution begins by initializing the main package and then invoking the function
main
. When that function invocation returns, the program exits. It does not wait for other (non-main
) goroutines to complete.
有关详细信息,请参阅
你必须告诉你的 main()
函数等待作为 goroutine 启动的 SayHello()
函数完成。您可以将它们与频道同步,例如:
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
}
备注:
根据您的 edits/comments:如果您希望 2 运行 SayHello()
函数随机打印 "mixed" 数字:您无法保证观察到此类行为。同样,
您可以尝试一下,但要知道结果不是确定性的。首先,您必须启用多个活动的 goroutines 以执行:
runtime.GOMAXPROCS(2)
其次,您必须首先将 SayHello()
作为 goroutine 启动,因为您当前的代码首先在主 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
或者(对于 icza 的回答)你可以使用 sync
包中的 WaitGroup
和匿名函数来避免改变原始 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()
}
Go 程序在 main
函数 returns.
一个选择是使用 sync.WaitGroup
之类的东西来等待 main
在 return 从 main
之前生成的其他 goroutines。
另一种选择是在 main
中调用 runtime.Goexit()
。来自 godoc:
Goexit terminates the goroutine that calls it. No other goroutine is affected. Goexit runs all deferred calls before terminating the goroutine. Because Goexit is not a panic, any recover calls in those deferred functions will return nil.
Calling Goexit from the main goroutine terminates that goroutine without func main returning. Since func main has not returned, the program continues execution of other goroutines. If all other goroutines exit, the program crashes.
这允许主 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 函数中永远阻塞要干净,尤其是对于无限的程序。一个缺点是,如果一个进程的所有 goroutines return 或退出(包括主 goroutine),Go 将检测到这是一个错误和恐慌:
fatal error: no goroutines (main called runtime.Goexit) - deadlock!
为避免这种情况,至少有一个 goroutine 必须在 return 之前调用 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()
}