Go 常规:select真的选择了一个随机案例吗?

Go 常规:select真的选择了一个随机案例吗?,go,select,goroutine,Go,Select,Goroutine,背景: 大家好,我正在按照上面的链接学习围棋 描述说“如果多个都准备好了,它会随机选择一个。” 但是,在使主例程等待2秒钟后,才调用func fibonacci。2秒后,通道应如下所示: c:10次呼叫以从频道获取价值 退出:0 在我看来,两个频道都准备好了。如果“如果多个已准备就绪,则随机选择一个”为真,则fibonacci中第一次调用案例将有50%的几率从退出通道获得0。然而,事实并非如此。所有10个数字在退出前都会打印出来。因此,选择看起来不是随机的。我错过什么了吗 package mai

背景:

大家好,我正在按照上面的链接学习围棋

描述说“如果多个都准备好了,它会随机选择一个。” 但是,在使主例程等待2秒钟后,才调用func fibonacci。2秒后,通道应如下所示: c:10次呼叫以从频道获取价值 退出:0

在我看来,两个频道都准备好了。如果“如果多个已准备就绪,则随机选择一个”为真,则fibonacci中第一次调用案例将有50%的几率从退出通道获得0。然而,事实并非如此。所有10个数字在退出前都会打印出来。因此,选择看起来不是随机的。我错过什么了吗

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,这是另一回事