Golang中无缓冲通道的接收操作是否有序?

Golang中无缓冲通道的接收操作是否有序? 是否有任何保证,这段代码不会因错误而崩溃?

我在规范中找不到任何证据表明无缓冲通道的接收操作是有序的,但这似乎是真的。我查看了 chan.go 的源代码,看起来阻塞的接收操作是有序的,因为它们被放置在一个链表 recvq 中,并按 FIFO 顺序从中取出。

有人能帮我解答一下吗?


更多关于Golang中无缓冲通道的接收操作是否有序?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

如果一个通道上有多个“读取者”,那么哪个读取者会看到下一个数据块是不确定的。

类似地,如果有多个“写入者”试图向一个已满的通道写入数据,那么哪个写入者会被允许将其数据交给通道也是不确定的。

更多关于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 的调度和通道的使用场景(如并发发送和接收)可能会影响实际观察到的顺序。但在纯阻塞接收的场景下,顺序是由运行时保证的。

回到顶部