Go Channel 写入超出其容量的数据

package main


import (

    "fmt"

)


func write(ch chan int) {

    for i := 0; i < 5; i++ {

        fmt.Println("avaliable", i)

        ch <- i

        fmt.Println("successfully wrote", i, "to ch")

    }


    close(ch)

}


func main() {

    ch := make(chan int)


    go write(ch)


    for v := range ch {

        fmt.Println("read value", v, "from ch")

    }

}

输出


avaliable 0

successfully wrote 0 to ch

avaliable 1

read value 0 from ch

read value 1 from ch

successfully wrote 1 to ch

avaliable 2

successfully wrote 2 to ch

avaliable 3

read value 2 from ch

read value 3 from ch

successfully wrote 3 to ch

avaliable 4

successfully wrote 4 to ch

read value 4 from ch

由于这是一个无缓冲的通道,它应该在数据写入它时立即阻塞,直到另一个 goroutine 从同一通道读取。但它接受的数据超出了它的能力。


预期行为


package main


import (

    "fmt"

    "time"

)


func write(ch chan int) {

    for i := 0; i < 5; i++ {

        fmt.Println("avaliable", i)

        ch <- i

        fmt.Println("successfully wrote", i, "to ch")

    }


    close(ch)

}


func main() {

    ch := make(chan int)


    go write(ch)


    time.Sleep(time.Second)


    for v := range ch {

        fmt.Println("read value", v, "from ch")


        time.Sleep(time.Second)

    }

}

输出


avaliable 0

read value 0 from ch

successfully wrote 0 to ch

avaliable 1

read value 1 from ch

successfully wrote 1 to ch

avaliable 2

read value 2 from ch

successfully wrote 2 to ch

avaliable 3

read value 3 from ch

successfully wrote 3 to ch

avaliable 4

read value 4 from ch

successfully wrote 4 to ch

如果在整个代码中放置了一些计时器,以便主 goroutine 在每次迭代之前被阻塞,它就会按预期工作。


绝地无双
浏览 230回答 2
2回答

HUX布斯

您无法从输出中推断出任何内容,因为“读取值”和“成功写入”Printfs 执行之间没有顺序保证。(在通道发送之前发生的“可用”Printf 和在相应通道接收之后发生的“读取值”Printf 之间存在一个,您可以看到输出中永远不会违反该顺序)。通道没有缓冲任何东西,因为它没有缓冲;只是通道发送完成后,两个不同的 goroutine 以不确定的顺序运行。有时发送方先走并打印“成功写入”消息,有时接收方先走并打印“读取值”消息。没有一个“领先”超过一个值,因为它们仍然在通道发送上完全同步;他们只是在比赛之后立即打印他们的状态消息。当您将 Sleep 调用添加到 main 时,它恰好使运行的 goroutinewrite在等待发送下一个值时总是被阻塞,而正在运行的 goroutinemain在调用时阻塞Sleep。当定时器超时时,主协程被唤醒,并立即发现它在通道上等待它的东西,抓住它,然后重新进入睡眠状态,然后write协程被唤醒。通过放慢速度,您已经让调度程序以一致的顺序运行事物(尽管这仍然部分是运气问题);没有睡眠,一切都尽可能快地运行,结果显然是随机的。

精慕HU

如果是这样的话,“睡眠”版本的输出会更加混乱。即使它们在某个点同步,您也不能期望两个独立线程的一致输出。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go