英文:
go lang, why go routine function never being called
问题
以下是翻译好的代码:
package main
import (
"fmt"
"runtime"
)
func say(s string) {
for i := 0; i < 5; i++ {
//runtime.Gosched()
fmt.Println(s)
}
}
func main() {
go say("world") // 创建一个新的goroutine
runtime.Gosched()
say("hello") // 当前的goroutine
}
为什么结果是:
hello
hello
hello
hello
hello
为什么没有输出world
?
回答:
如果我这样修改代码,就可以输出world
了:
package main
import (
"fmt"
"runtime"
)
func say(s string) {
for i := 0; i < 5; i++ {
//runtime.Gosched()
fmt.Println(s)
}
}
func main() {
go say("world") // 创建一个新的goroutine
runtime.Gosched()
say("hello") // 当前的goroutine
}
英文:
package main
import (
"fmt"
//"runtime"
)
func say(s string) {
for i := 0; i < 5; i++ {
//runtime.Gosched()
fmt.Println(s)
}
}
func main() {
go say("world") // create a new goroutine
say("hello") // current goroutine
}
Why result is:
> hello
> hello
> hello
> hello
> hello
Why is there no world
?
Answer: (edited:)
If I do this, it is good now:
package main
import (
"fmt"
"runtime"
)
func say(s string) {
for i := 0; i < 5; i++ {
//runtime.Gosched()
fmt.Println(s)
}
}
func main() {
go say("world") // create a new goroutine
runtime.Gosched()
say("hello") // current goroutine
}
答案1
得分: 2
你只是遇到了一个时间问题,因为你没有“协调”你的go程。处理这个问题的常见方法是使用等待组(wait group)。另一种选择是使用通道和阻塞选择(blocking select)。一个使用等待组的实现可能如下所示:
func main() {
wg := sync.WaitGroup{}
wg.Add(1)
go say("world") // 创建一个新的goroutine
wg.Add(1)
say("hello") // 当前的goroutine
wg.Wait()
}
而通道选项(在这个例子中实际上并不有趣或有用)可能是这样的:
func main() {
done := make(chan bool)
go say("world", done) // 创建一个新的goroutine
say("hello", done) // 当前的goroutine
select {
case fin := <-done:
// 完成时的操作
return
}
}
func say(s string, done chan bool) {
for i := 0; i < 5; i++ {
fmt.Println(s)
}
done <- true
}
然而,上面的例子中,第一个调用say完成后,程序就会结束执行。要确保两个都完成,你需要给它们传递不同的通道,并在两个通道上进行阻塞读取。这更像是一种模式,当你的go程正在做实际工作,并且你想要从它们那里获取数据或需要更复杂的协调(例如基于先前结果生成新的goroutine等)时,我会使用这种模式。
英文:
You're just experiencing a timing issue because you're not 'coordinating' your go routines. The common way to handle this is with a wait guard. The other option I see from time to time using channels and a blocking select. A wait guard implementation would look something like this;
func main() {
wg := sync.WaitGroup{}
wg.Add(1)
go say("world") // create a new goroutine
wg.Add(1)
say("hello") // current goroutine
wg.Wait()
}
While the channel option (not actually interesting or useful in this example) is something more like this;
func main() {
done := make(chan bool)
go say("world", done) // create a new goroutine
say("hello", done) // current goroutine
select {
case fin := <- done:
//on finished
return
}
}
func say(s string, chan bool) {
for i := 0; i < 5; i++ {
fmt.Println(s)
}
done <- true
}
With the example above though, the first call to say completing would allow the program to finish executing. To ensure both finish you'd have to pass different channels to each and have blocking reads on both. This is more a pattern I would use when your go routines are doing real work and you want to bring data to aggregate data from them or need more complex coordination (like spawning new goroutines based on the results of previous ones ect).
答案2
得分: 1
你没有允许goroutine在main()
退出之前运行。
尽管对say
的第二次调用会阻塞(短暂),但不能保证第一个goroutine能够运行。你需要等待两个goroutine都返回,通常可以使用WaitGroup来实现。
var wg sync.WaitGroup
func say(s string) {
defer wg.Done()
for i := 0; i < 5; i++ {
//runtime.Gosched()
fmt.Println(s)
}
}
func main() {
wg.Add(1)
go say("world") // 创建一个新的goroutine
wg.Add(1)
say("hello") // 当前的goroutine
wg.Wait()
}
英文:
You're not allowing the goroutine to run before main()
exits.
Even though the second call to say
blocks (briefly), there's no guarantee that the first goroutine can run. You need to wait for both to return, which is often done with a WaitGroup
var wg sync.WaitGroup
func say(s string) {
defer wg.Done()
for i := 0; i < 5; i++ {
//runtime.Gosched()
fmt.Println(s)
}
}
func main() {
wg.Add(1)
go say("world") // create a new goroutine
wg.Add(1)
say("hello") // current goroutine
wg.Wait()
}
答案3
得分: 0
这是因为主 goroutine 退出得太早了。当主 goroutine 退出时,进程也会退出,所以其他 goroutine 没有机会运行。如果你希望 goroutine 运行,就要保持主程序足够长的时间。
package main
import (
"fmt"
"runtime"
)
func say(s string) {
for i := 0; i < 5; i++ {
fmt.Println(s)
}
}
func main() {
go say("world") // 创建一个新的 goroutine
runtime.Gosched()
say("hello") // 当前 goroutine
time.Sleep(1 * time.Second) // 这一行
}
英文:
It's because the main goroutine exits too early. When the main goroutine exits, the process will exit, so there is no chance for other goroutines to run. If you wish the goroutines to run, keep the main routine alive long enough.
package main
import (
"fmt"
"runtime"
)
func say(s string) {
for i := 0; i < 5; i++ {
fmt.Println(s)
}
}
func main() {
go say("world") // create a new goroutine
runtime.Gosched()
say("hello") // current goroutine
time.Sleep(1 * time.Second) // this line
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论