奇怪的选择情况下的默认行为[关闭]

问题描述 投票:-4回答:2
有人可以向我解释奇怪的select-case-default行为吗?如果我将fmt.printf(%v \ n放在某些情况下),它将永远不会到达默认阶段并超时。但是,如果我推迟或评论printf,那就可以了。截图:bad codecommenteddefered和我在o游乐场的代码https://play.golang.org/p/FYsToHUJE43
go goroutine
2个回答
1
投票
您的代码包含潜在的死锁,如果您的非默认情况足够慢(例如,在执行IO操作的情况下,则最终会发生这种情况。

问题是,如果某个通道关闭,则从该特定通道读取会导致nil, false对。如果两个通道都关闭,那么您将永远不会遇到默认情况,因为您的选择将在两个失败的读取之间交替,从而导致无限循环。

如果注释掉fmt.Printf()函数,则for循环会非常快,以至于(但不能保证!)您可以在收集足够的树项之后但在Walk()函数关闭通道之前进入循环因此输入默认大小写并中断循环。我试图给出一个可能的执行命令的示例,该命令将在下面完成其运行。

\\ t1 - thread of Walk(tree1) \\ t2 - thread of Walk(tree2) \\ t3 - thread of the loop t1 > c.send() t2 > c.send() t3 > handle c1 t3 > handle c2 t3 > default, break t1 > c.close() t2 > c.close()

但是,放回IO操作会大大降低for循环的速度,以至于在关闭两个通道之前将没有机会输入select语句,因此它陷入了无限循环。现在发生的事情是这样的:

t1 > c.send() t2 > c.send() t3 > handle c1 // long IO operation t1 > c.close() t3 > handle c2 // long IO operation t2 > c.close() t3 > handle c1 with error t3 > handle c1 with error t3 > handle c2 with error ...

您应该在select语句之外处理中断条件。

0
投票
您应该只检查是否已完成循环条件:

for i1 < 10 || i2 < 10 { select { case x, ok := <-c1: if ok { fmt.Printf("ch1->%v i= %v\n", x, i1) tre1[i1] = x i1++ } case y, ok := <-c2: if ok { fmt.Printf("ch2->%v i= %v\n", y, i2) tre2[i2] = y i2++ } } }

© www.soinside.com 2019 - 2024. All rights reserved.