英文:
Strange Goroutines Behaviour
问题
请纠正我如果我错了。据我所知,goroutine的工作方式与线程大致相似。所以如果我用不同的参数生成相同的函数,并在前面加上go,它应该能正常工作吗?
实际输出:
rahul@g3ck0:~/programs/go$ go run goroutine.go
rahul@g3ck0:~/programs/go$
我只得到了提示符。
预期输出:
direct : 0
direct : 1
direct : 2
redirect : 0
redirect : 1
redirect : 2
不一定是相同的顺序。
无法理解这种奇怪的行为。我有什么遗漏吗?
编辑:添加一个Scan语句可以解决这个问题。但有没有更好的方法?
英文:
Please correct me if I am wrong. As long as I know, goroutine works roughly similar to threads. So If I spawn the same function with different parameters prefixing with go. It should work perfectly fine ?
package main
import "fmt"
func f(from string) {
for i := 0; i < 3; i++ {
fmt.Println(from, ":", i)
}
}
func main() {
go f("direct")
go f("redirect")
//var input string
//fmt.Scanln(&input)
}
Actual Output:
rahul@g3ck0:~/programs/go$ go run goroutine.go
rahul@g3ck0:~/programs/go$
I just get back prompt.
Expected output:
direct : 0
direct : 1
direct : 2
redirect : 0
redirect : 1
redirect : 2
Not necessarily in the same order.
Not able to understand this strange behaviour. Am I missing something ?
EDIT: Adding a Scan statement resolves it. But is there any better way of doing it ?
答案1
得分: 6
当主函数退出时,程序会终止,不管其他goroutine的状态如何。您可以通过在主函数的末尾添加select{}
来测试这一点。这将导致主函数永远不会退出,您将看到其他goroutine运行。
如果您希望在两个goroutine完成时程序能够干净地退出(避免死锁),您需要使用类似通道或sync.WaitGroup的机制来协调主函数在所有任务完成后结束。
使用sync.WaitGroup的示例:
package main
import (
"fmt"
"sync"
)
func f(from string, wg *sync.WaitGroup) {
for i := 0; i < 3; i++ {
fmt.Println(from, ":", i)
}
wg.Done()
}
func main() {
wg := new(sync.WaitGroup)
wg.Add(2)
go f("direct", wg)
go f("redirect", wg)
wg.Wait()
}
使用通道的示例:
package main
import (
"fmt"
)
func f(from string, ch chan<- bool) {
for i := 0; i < 3; i++ {
fmt.Println(from, ":", i)
}
ch <- true
}
func main() {
ch := make(chan bool)
go f("direct", ch)
go f("redirect", ch)
<-ch
<-ch
}
英文:
When main exits, the program terminates regardless of the state of other goroutines. You can test this by adding select{}
at the end of your main function. This will cause main to never exit and you will see the other goroutines run.
If you want your program to exit cleanly (without a deadlock) when both goroutines complete, you need to use something like a channel or sync.Waitgroup to coordinate main ending when everything is complete.
Example using sync.Waitgroup:
package main
import (
"fmt"
"sync"
)
func f(from string, wg *sync.WaitGroup) {
for i := 0; i < 3; i++ {
fmt.Println(from, ":", i)
}
wg.Done()
}
func main() {
wg := new(sync.WaitGroup)
wg.Add(2)
go f("direct", wg)
go f("redirect", wg)
wg.Wait()
}
Example using channels:
package main
import (
"fmt"
)
func f(from string, ch chan<- bool) {
for i := 0; i < 3; i++ {
fmt.Println(from, ":", i)
}
ch <- true
}
func main() {
ch := make(chan bool)
go f("direct", ch)
go f("redirect", ch)
<-ch
<-ch
}
答案2
得分: 0
如上所述,最后的select{}确保输出被显示,但是你不能期望go routines按特定顺序运行。
如果你并行运行go routines,它们的运行顺序是不确定的。你不能期望它们按顺序运行,因为它们是并行运行的!
你可能会在一台机器上一次又一次地得到预期的输出,但是不能保证在任何给定的机器上每次都按顺序打印输出!
英文:
As stated above the select{} in the end makes sure output is displayed, but you cannot expect the go routines to run in a special order.
If you run parallell go routines there is never any guarantee in what order they will run. You cannot except them to run in a sequential order, because they run in parallell!
You might get the expected output time after time on one machine, but there is no guarantee that the printouts come in order every time on any given machine!!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论