Go 常规:select真的选择了一个随机案例吗?
背景: 大家好,我正在按照上面的链接学习围棋 描述说“如果多个都准备好了,它会随机选择一个。” 但是,在使主例程等待2秒钟后,才调用func fibonacci。2秒后,通道应如下所示: c:10次呼叫以从频道获取价值 退出:0 在我看来,两个频道都准备好了。如果“如果多个已准备就绪,则随机选择一个”为真,则fibonacci中第一次调用案例将有50%的几率从退出通道获得0。然而,事实并非如此。所有10个数字在退出前都会打印出来。因此,选择看起来不是随机的。我错过什么了吗Go 常规:select真的选择了一个随机案例吗?,go,select,goroutine,Go,Select,Goroutine,背景: 大家好,我正在按照上面的链接学习围棋 描述说“如果多个都准备好了,它会随机选择一个。” 但是,在使主例程等待2秒钟后,才调用func fibonacci。2秒后,通道应如下所示: c:10次呼叫以从频道获取价值 退出:0 在我看来,两个频道都准备好了。如果“如果多个已准备就绪,则随机选择一个”为真,则fibonacci中第一次调用案例将有50%的几率从退出通道获得0。然而,事实并非如此。所有10个数字在退出前都会打印出来。因此,选择看起来不是随机的。我错过什么了吗 package mai
package main
import "fmt"
import "time"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
time.Sleep(2 * time.Second)
fibonacci(c, quit)
}
主程序包
输入“fmt”
导入“时间”
func-fibonacci(c,int){
x、 y:=0,1
为了{
挑选{
案例c您创建了一个无缓冲的chan
:
c := make(chan int)
这意味着任何从禅宗那里读到的东西都会被阻止,直到有东西被写入禅宗。而任何向禅宗写信的东西都会被阻止,直到有东西从禅宗那里读到
因此,在本法典中:
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
在此基础上,它交替来回阻塞读取一个值,写入一个值,直到读取10个值,然后将0
发送到quit
要创建缓冲chan,需要指定缓冲区的大小
c := make(chan int, 10)
但请注意,即使您这样做,它也不会像您预期的那样运行,因为在写入退出之前,您正在读取所有10个值。您需要将写入程序放在同一位置,而将读取程序放在同一位置,而不是将它们混淆。您创建了一个无缓冲chan
:
c := make(chan int)
这意味着任何从禅宗那里读到的东西都会被阻止,直到有东西被写入禅宗。而任何向禅宗写信的东西都会被阻止,直到有东西从禅宗那里读到
因此,在本法典中:
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
在此基础上,它交替来回阻塞读取一个值,写入一个值,直到读取10个值,然后将0
发送到quit
要创建缓冲chan,需要指定缓冲区的大小
c := make(chan int, 10)
但是请注意,即使您这样做,它也不会像您期望的那样运行,因为在写入quit
之前,您正在读取所有10个值。您需要将写入程序放在同一位置,而将读取程序放在同一位置,而不是将它们混淆。在代码的第一个片段中,quit
在之前从未准备好对于
循环。并且,在循环的每次迭代中,c
都准备好了,并且将阻塞,直到发送一个数字。因此,select
除了写入c
之外,真的什么都做不了。如果你睡两秒钟,这根本没关系
第二段代码没有被窃听。select
确实会随机选取一个案例。但是,Go Playerd有一个固定的随机生成器,这意味着,在Playerd上,select在每次运行时都会选取一个特定的案例。在您的第一段代码中,quit
在for
循环之前从未准备好。而且,在循环的每次迭代中,c
都已准备就绪,并将一直阻止,直到发送一个数字。因此,select
除了写入c
之外,实际上什么都做不了。如果你睡两秒钟,这一点都不重要
第二段代码没有被窃听。select
确实会随机选取一个案例。然而,Go Playerd有一个固定的随机生成器,这意味着,在Playerd上,select在每次跑步中都会选取一个特定的案例。我认为你对你的主要方法中发生的事情错了……我要详细分析一下我认为是什么继续澄清
func main() {
c := make(chan int)
quit := make(chan int) // make a couple channels
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c) // blocked here in goroutine
}
quit <- 0
}() // go func { ... }() - you're both writing this closure and invoking it as a goroutine
time.Sleep(2 * time.Second) // sleep for 2 seconds
fibonacci(c, quit) // call fibonacci passing in the channels
}
func main(){
c:=制造(成交量)
quit:=make(chan int)//制作两个频道
go func(){
对于i:=0;i<10;i++{
Println(我认为你对你的主要方法中发生的事情是错误的……为了清楚起见,我将对我认为发生的事情进行分解
func main() {
c := make(chan int)
quit := make(chan int) // make a couple channels
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c) // blocked here in goroutine
}
quit <- 0
}() // go func { ... }() - you're both writing this closure and invoking it as a goroutine
time.Sleep(2 * time.Second) // sleep for 2 seconds
fibonacci(c, quit) // call fibonacci passing in the channels
}
func main(){
c:=制造(成交量)
quit:=make(chan int)//制作两个频道
go func(){
对于i:=0;i<10;i++{
fmt.Println(为什么您认为两个频道都准备好了?quit
没有准备好,因为没有goroutine正在写入它。我相信它已经准备好了,因为主例程已经等待了2秒钟,edit:这应该足够让then go func例程完成了……对吧?不,goroutine无法完成,因为它正在等待有人将值写入c
。请参阅相关/可能重复:为什么您认为两个频道都准备好了?quit
没有准备好,因为没有goroutine正在写入它。我认为它准备好了,因为主例程已经等待了2秒钟,edit:这应该足以让then go func例程完成…对吗?不,goroutine无法完成,因为它正在等待某个人ne将值写入c
。请参阅相关/可能的重复:被缓冲的通道没有任何区别,他的goroutine仍然卡在循环中,重复读取c
,然后在退出时发送的主goroutine中的代码行才能运行。是的,正如您所评论的,我正在解决这一问题。这实际上是两个问题。对于无缓冲通道,您需要3个goroutine。一个goroutine使c
准备就绪(从中读取),一个goroutine使quit
准备就绪(写入),一个goroutine来执行选择
。只有两个goroutine,你无法完成所有三个goroutine,因此只有一个chan将准备就绪。不,这与缓冲无关,运行时仍然有一个排序的概念。请查看我刚刚编写的示例程序,以测试这一点;-当我的睡眠时间为100ms时,它会每分钟产生一个磁头我,如果我把它设为1000毫秒,它每次都会产生尾巴。如果这被认为是“伪随机的”,那么go开发者需要在他们的实现中解决一个bug,这是另一回事