看无闻的Go教程中提到,Go的select对channel的操作,是随机的。我测试的时候,在select中对channel写数据,确实是随机的。但是,我还想证实一下,select对channel的读,也是随机的。下面是一个例子,我通过goroutine,对ch1和ch2两个channel读取数据。为了避免ch1和ch2刚顺序写完就被读出来,影响实验的准确性。我特意在goroutine中使用了timeout。但是我发现两个问题:
①:最终还是先输出ccc,再输出ddd,运行多少次都是一样。我的理解,虽然goroutine后台去执行了,但是休眠5s的过程中,ch1和ch2都已经有值了,那么休眠结束后,理应会随机先输出ccc或者ddd啊
②:关于timeout,我用sublime的插件gosublime开发,发现运行开始到结束,都是一下子输出的,没有体现出来时间停顿一个一个输出这个现象,但是,在Wide(http://studygolang.com/wide/playground )里面运行下面的代码,就是一个一个输出的,并非一下子都输出出来,这又是为什么?
package main
import "fmt"
import "time"
func main() {
//定义两个字符串类型的channel
ch1, ch2 := make(chan string, 0), make(chan string, 0)
//启用goruntine不断从两个channel中读取数据
go func() {
fmt.Println("start")
time.Sleep(5 * time.Second)
fmt.Println("wait")
time.Sleep(2 * time.Second)
//i := 1
for {
// fmt.Println(i)
// i++
select {
case v, ok := <-ch1:
if ok {
fmt.Println(ok, v)
} else {
fmt.Println("!!!!")
}
case v, ok := <-ch2:
if ok {
fmt.Println(ok, v)
} else {
fmt.Println("~~~~")
}
}
}
}()
//time.Sleep(2 * time.Second)
ch1 <- "cccc"
ch2 <- "dddd"
time.Sleep(1 * time.Second)
fmt.Println("end")
}
有疑问加站长微信联系(非本文作者)

@Unknown @88250
这个程序 有问题,你的 case 的 else 部分永远得不到执行。所以 根本不能证明什么。给你加上 close(ch1);close(ch2)就可以了
麻烦贴一下 Playground 分享的链接。
你这里明显有问题,想要实现你说的效果,channel得定义为有缓存的,如:
ch1, ch2 := make(chan string, 1), make(chan string, 1)
我想这样应该能清晰说明你想要证明的问题了:
<iframe style="border:1px solid" src="https://wide.b3log.org/playground/aa049199d5efd71cb331a75cddf66ef2.go?embed=true" width="100%" height="600"></iframe>
其实我并没想让else执行,而且如果把ch1和ch2关闭,goroutine中的for将出现死循环,直到程序退出吧?因为close之后,select将永远拿到零值。这是其一,其二,能否给一个例子,说明select是随机从channel中取数据的?
为什么?goroutine本身就在读取数据,这就意味着ch1 <- "cccc",ch2 <- "dddd"执行之后,goroutine所执行的函数可以在1秒之后,读取channel的数据。这个时候,相当于两个channel都有数据,select不是应该随机取一个吗?
http://dwz.cn/Em4YW
<iframe style="border:1px solid" src="https://wide.b3log.org/playground/ffcc15158f19aae4327982f4329499cd.go?embed=true" width="100%" height="600"></iframe>
好像还是不可以,是我哪里理解有问题吗?select的随机取值,按照你提供的代码来看,最后应该输出ddd和ccc顺序每次都不一样的。可我执行了十几次,每次结果都是ddd之后才ccc啊
select永远拿0值,从两个 case 里面随机拿。说明进入两个 case 是随机的。
多执行几次: http://dwz.cn/EmIiu
你想当然了。无缓存的channel,并不是你按你说的执行的。
无缓存,到ch1必定阻塞,所以不用说,ch1的内容先输出,肯定达不到你想要测试的预期
无缓存ch1必定阻塞没错,关键是读取ch1的是goroutine。这个 @88250 已经给予解答了
达到我想要的预期结果了,看来还是我试的次数少。非常感谢~
@663280439 你不觉得 @88250 的解答,是把无缓存的 channel 改为了 有缓存的 channel 了吗?