意外的Goroutine行为
我是戈朗的初学者 我在读Go from中的并发性 事情一直进展顺利,直到有人向我提出关于意外的Goroutine行为,go,goroutine,Go,Goroutine,我是戈朗的初学者 我在读Go from中的并发性 事情一直进展顺利,直到有人向我提出关于 问题是:找出两个给定的二叉树是否相等。 我的方法是:按顺序遍历,将两棵树的值保存在一个切片中,然后比较它们 以下是我的解决方案:[不完整] package main import ( "fmt" "golang.org/x/tour/tree" ) // Walk walks the tree t sending all values // from the tree to the ch
问题是:找出两个给定的二叉树是否相等。
我的方法是:按顺序遍历,将两棵树的值保存在一个切片中,然后比较它们 以下是我的解决方案:[不完整]
package main
import (
"fmt"
"golang.org/x/tour/tree"
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
if t != nil {
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right, ch)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
fmt.Println("executing first go routing")
Walk(t1, ch1)
fmt.Println("closing channel [ch1]")
close(ch1)
}()
go func() {
fmt.Println("executing second go routing")
Walk( t2, ch2 )
fmt.Println("closing channel [ch2]")
close(ch2)
}()
shouldContinue := true
var continue1, continue2 bool
for shouldContinue {
select {
case r1, ok1 := <-ch1:
fmt.Println("[ch1] [rcvd]", r1)
continue1 = ok1
case r2, ok2 := <-ch2:
fmt.Println("[ch2] [rcvd]", r2)
continue2 = ok2
}
shouldContinue = continue1 || continue2
}
return true
}
func main() {
Same(tree.New(1), tree.New(1))
}
有人能解释一下这是怎么回事吗?一旦通道2关闭,第二个go例程完成,为什么第一个不执行
任何帮助都将不胜感激。多谢各位
更新:我在谷歌上搜索关于跳出频道的信息,我发现了一个很难回答的问题 据此,我更新了我的解决方案如下:
package main
import (
"fmt"
"golang.org/x/tour/tree"
// "time"
)
// Walk walks the tree t sending all values
// from the tree to the channel ch.
func Walk(t *tree.Tree, ch chan int) {
// time.Sleep(time.Millisecond)
if t != nil {
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right, ch)
}
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
fmt.Println("executing first go routing")
Walk(t1, ch1)
fmt.Println("closing channel [ch1]")
close(ch1)
}()
go func() {
fmt.Println("executing second go routing")
Walk( t2, ch2 )
fmt.Println("closing channel [ch2]")
close(ch2)
}()
for {
select {
case r1, ok1 := <-ch1:
fmt.Println("[ch1] [rcvd]", r1)
if !ok1 {
ch1 = nil
}
case r2, ok2 := <-ch2:
fmt.Println("[ch2] [rcvd]", r2)
if !ok2 {
ch2 = nil
}
}
if ch1 == nil && ch2 == nil {
break
}
}
return true
}
func main() {
Same(tree.New(1), tree.New(1))
}
我现在对正在发生的事情更加困惑
一旦通道2关闭,为什么第一个不被执行
不执行通道。反复执行的是您的选择。请注意,无论通道是否关闭,这两种情况都可以始终执行。因此,select可以选择第二个案例,id选择了该案例,您中止了该案例。(您的中止条件看起来可疑:一旦两个通道都关闭,即如果ok1和ok2都为false,则终止)
不要将select本身视为“goroutine调度工具”。事实并非如此。它将随机选择一个可运行的案例。如果您的所有案例都是val形式,则确定:=
一旦通道2关闭,为什么第一个不被执行
不执行通道。反复执行的是您的选择。请注意,无论通道是否关闭,这两种情况都可以始终执行。因此,select可以选择第二个案例,id选择了该案例,您中止了该案例。(您的中止条件看起来可疑:一旦两个通道都关闭,即如果ok1和ok2都为false,则终止)
不要将select本身视为“goroutine调度工具”。事实并非如此。它将随机选择一个可运行的案例。若您的所有案例的形式都是val,ok:=在代码的第一部分,则逻辑中存在错误
shouldContinue := true
var continue1, continue2 bool
for shouldContinue {
select {
case r1, ok1 := <-ch1:
fmt.Println("[ch1] [rcvd]", r1)
continue1 = ok1
case r2, ok2 := <-ch2:
fmt.Println("[ch2] [rcvd]", r2)
continue2 = ok2
}
shouldContinue = continue1 || continue2
}
频道关闭后,您无法在此频道上发送值,但仍可从该频道接收。请参见此处:
Nil通道始终处于阻塞状态,并且您更改了环路中断逻辑的。这就是第二个解决方案工作的原因。在代码的第一部分中,逻辑有错误
shouldContinue := true
var continue1, continue2 bool
for shouldContinue {
select {
case r1, ok1 := <-ch1:
fmt.Println("[ch1] [rcvd]", r1)
continue1 = ok1
case r2, ok2 := <-ch2:
fmt.Println("[ch2] [rcvd]", r2)
continue2 = ok2
}
shouldContinue = continue1 || continue2
}
频道关闭后,您无法在此频道上发送值,但仍可从该频道接收。请参见此处:
Nil通道始终处于阻塞状态,并且您更改了环路中断逻辑的。这就是为什么您的第二个解决方案有效。年轻玩家有用的书签:年轻玩家有用的书签:感谢您的努力。为什么第一个不被处决?这是我在问题后面纠正的一个打字错误。谢谢你的努力。为什么第一个不被处决?是一个打字错误,我后来在问题中更正了。谢谢。这个答案也很有帮助+谢谢你。这个答案也很有帮助+1.
shouldContinue := true
var continue1, continue2 bool
for shouldContinue {
select {
case r1, ok1 := <-ch1:
fmt.Println("[ch1] [rcvd]", r1)
continue1 = ok1
case r2, ok2 := <-ch2:
fmt.Println("[ch2] [rcvd]", r2)
continue2 = ok2
}
shouldContinue = continue1 || continue2
}
continue1 = true
continue2 = true
for shouldContinue {
select {
case r1, ok1 := <-ch1:
fmt.Println("[ch1] [rcvd]", r1)
continue1 = ok1
case r2, ok2 := <-ch2:
fmt.Println("[ch2] [rcvd]", r2)
continue2 = ok2
}
shouldContinue = continue1 || continue2
}