看无闻的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 )里面运行下面的代码,就是一个一个输出的,并非一下子都输出出来,这又是为什么?
```go
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")
}
```
<a href="/user/Unknown" title="@Unknown">@Unknown</a> <a href="/user/88250" title="@88250">@88250</a>
#1
更多评论
这个程序 有问题,你的 case 的 else 部分永远得不到执行。所以 根本不能证明什么。给你加上 close(ch1);close(ch2)就可以了
```go
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"
close(ch1)
close(ch2)
time.Sleep(1 * time.Second)
fmt.Println("end")
}
```
#2