通道缓冲区的值比Go中的预期值多
问题描述:
I thought that channels in Go only hold 1 value by default unless the buffer size if specified. I read that here. But when I run this:
func main (){
for i := range numGen(6) {
log.Println("taking from channel", i)
}
}
func numGen(num int) chan int {
c := make(chan string)
go func() {
for i := 0; i < num; i++ {
log.Println("passing to channel", i)
c <- i
}
close(c)
}
return c
}
my output is:
2017/06/13 18:09:08 passing to channel 0
2017/06/13 18:09:08 passing to channel 1
2017/06/13 18:09:08 taking from channel 0
2017/06/13 18:09:08 taking from channel 1
2017/06/13 18:09:08 passing to channel 2
2017/06/13 18:09:08 passing to channel 3
2017/06/13 18:09:08 taking from channel 2
2017/06/13 18:09:08 taking from channel 3
2017/06/13 18:09:08 passing to channel 4
2017/06/13 18:09:08 passing to channel 5
2017/06/13 18:09:08 taking from channel 4
2017/06/13 18:09:08 taking from channel 5
which shows that the channel is holding 2 values at a time. Specifying a buffer size like this
c := make(chan int, 0)
does nothing. Any way I could make it only hold 1, value, not 2?
答
which shows that the channel is holding 2 values at a time.
Thats not the case. This is how the code executes:
- The main goroutine blocks on a read on the channel
- The second goroutine writes to the channel and continues executing.
- The second goroutine blocks at the second write attempt because noone is reading
- The main goroutine continues executing, prints the read number
- The main goroutine reads another number since someone is writing to it
- The main goroutine prints the read number and blocks on the next read
- The second goroutine continues executing at step 2.
There is no buffer, just concurrency.
答
package main
import (
"log"
)
func main() {
seq := make(chan bool)
for i := range numGen(6, seq) {
<-seq
log.Println("taking from channel", i)
}
}
func numGen(num int, seq chan bool) chan int {
c := make(chan int)
go func() {
for i := 0; i < num; i++ {
c <- i
log.Println("passing to channel", i)
seq <- true // 要保证顺序,这里发送一个信号量。
}
close(c)
}()
return c
}