buffered channel的工作模式疑问?
来源:11-1 channel

拧壶冲
2020-11-22
buffered channel有缓冲区,缓存区满了,才会阻塞。
- 那这样是不是可以理解「channel的发送」其实也是一种goroutine阻塞的操作?
- 不带buffer 的channel因为没有缓冲区,所以channel发送数据时立刻就阻塞?
- 带buffer的channel,当缓冲区收满后,才会停止阻塞,然后接受的操作也是一次性把缓冲区的全部读完?
- 从内存模型看, 一下代码有两种情况,我有疑惑:
A send on a channel happens before the corresponding receive from that channel completes.
var c = make(chan int, 3)
var a string
func f() {
a = "hello, world"
c <- 0
}
func main() {
go f()
<-c
print(a)
}
这里说「发送」happens-before「接收」。是不是就可以理解,可执行的代码上先有「发送」,然后才执行接收?
但是又有一个rule:
The kth receive on a channel with capacity C happens before the k+Cth send from that channel completes.
var work []func()
var limit = make(chan int, 3)
func main() {
work = []func(){
func() {
fmt.Println("Work1")
time.Sleep(time.Second)
},
func() {
fmt.Println("Work2")
time.Sleep(time.Second)
},
func() {
fmt.Println("Work3")
time.Sleep(time.Second)
},
func() {
fmt.Println("Work4")
time.Sleep(time.Second)
},
}
wg := sync.WaitGroup{}
for _, w := range work {
wg.Add(1)
go func(w func()) {
limit <- 1
w()
<-limit
wg.Done()
}(w)
}
wg.Wait()
}
这里又说接收「第k次的接收」happens-before「k+缓冲区size的发送」。这里是不是在限定,在第一轮“缓冲区满时”的接收必须happens-before在第二轮发送的开始?
2回答
-
同学理解的很透彻了,尤其是对Go Memory Model的理解。这个问题非常好。
那这样是不是可以理解「channel的发送」其实也是一种goroutine阻塞的操作?unbuffered channel的发送是阻塞操作,发送的时刻立刻阻塞。buffered channel可以等到buffer满了才阻塞。
带buffer的channel,当缓冲区收满后,才会停止阻塞,然后接受的操作也是一次性把缓冲区的全部读完?这句话说反了,而且不严密。
发送方:缓冲区未满,可以不阻塞。注意我说可以,不是必须不阻塞。但实际情况下,通常都是不阻塞的。
接收方:不存在“一次性”这种说法。buffered channel仍然可以做成发一个数据,立刻goroutine切换,然后接收方收一个数据。但是为了性能,通常来说会观察到类似“一次性”收完的这种行为。
我们看你没有贴出来的那个例子:
var c = make(chan int, 1) // If the channel were buffered。所以我这里加一个1,看看结果
var a string
func f() {
a = "hello, world"
<-c
}
func main() {
go f()
c <- 0
print(a)
}他说:
If the channel were buffered (e.g., c = make(chan int, 1)) then the program would not be guaranteed to print "hello, world". (It might print the empty string, crash, or do something else.)
按照你“一次性”收完的理解,这里似乎应该永远不会看到打印出hello world。但他的说法是不保证打印hello world,也是might打印空串,crash,等。不过实际上,我们很难观测到这段程序会打出hello world。
222021-01-09 -
ccmouse
2020-11-23
A send on a channel happens before the corresponding receive from that channel completes.
和
The kth receive on a channel with capacity C happens before the k+Cth send from that channel completes.
你是不是觉得这两条规则冲突了?
第一条规则没说是不是buffered,所以都适用,就是说先有发送,再有接收的意思。
第二条规则,你的说法虽然不严密,但它其实想表达的的确是这个意思。(当然,这句话用人话永远都说不严密)。这里的C应该必须>0,也就是必须buffered,这样两条规则就没有冲突。第一条规则讲的是同一“次”发送必须发生在这一“次”接收之前。第二条规则不严密的说法就是“一轮”接收必须发生在”下一轮“发送之前。
222021-07-16
相似问题