Golang中无缓冲通道的接收操作是否有序?
Golang中无缓冲通道的接收操作是否有序? 是否有任何保证,这段代码不会因错误而崩溃?
我在规范中找不到任何证据表明无缓冲通道的接收操作是有序的,但这似乎是真的。我查看了 chan.go 的源代码,看起来阻塞的接收操作是有序的,因为它们被放置在一个链表 recvq 中,并按 FIFO 顺序从中取出。
有人能帮我解答一下吗?
更多关于Golang中无缓冲通道的接收操作是否有序?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
如果一个通道上有多个“读取者”,那么哪个读取者会看到下一个数据块是不确定的。
类似地,如果有多个“写入者”试图向一个已满的通道写入数据,那么哪个写入者会被允许将其数据交给通道也是不确定的。
更多关于Golang中无缓冲通道的接收操作是否有序?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
是的,无缓冲通道的接收操作是有序的。Go 语言规范虽然没有明确说明这一点,但通过运行时实现可以确认这一点。在 chan.go 的源代码中,阻塞的接收操作确实被维护在一个 recvq 链表中,该链表遵循 FIFO(先进先出)顺序。这意味着当多个 goroutine 在同一个无缓冲通道上阻塞等待接收数据时,它们会被唤醒的顺序与它们开始等待的顺序一致。
以下是一个示例代码,演示了无缓冲通道接收操作的有序性:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
ch := make(chan int)
var wg sync.WaitGroup
// 启动多个接收者 goroutine
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
value := <-ch
fmt.Printf("接收者 %d 接收到值: %d\n", id, value)
}(i)
}
// 等待所有接收者就绪
time.Sleep(time.Second)
// 发送数据到通道
for i := 0; i < 5; i++ {
ch <- i
}
wg.Wait()
}
在这个示例中,多个 goroutine 在无缓冲通道 ch 上阻塞等待接收数据。尽管 goroutine 的启动顺序可能因调度器而有细微差异,但通过添加短暂的延迟(time.Sleep),可以确保接收者 goroutine 在发送数据前都已进入阻塞等待状态。运行此代码,输出通常会显示接收者按照启动顺序(0 到 4)依次接收到值,这验证了接收操作的有序性。
需要注意的是,虽然接收操作在阻塞情况下是有序的,但 goroutine 的调度和通道的使用场景(如并发发送和接收)可能会影响实际观察到的顺序。但在纯阻塞接收的场景下,顺序是由运行时保证的。

