Golang中channel的顺序问题
Golang中channel的顺序问题 我不理解为什么不能按我想要的任意顺序从通道读取数据。我已经向通道发送了值。为什么必须保持相同的顺序?谢谢
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go send(ch1, ch2)
// 这个顺序是有效的
fmt.Println(<- ch1)
fmt.Println(<- ch2)
// 这个顺序是无效的
fmt.Println(<- ch1)
fmt.Println(<- ch1)
}
func send(ch1, ch2 chan<- int) {
for i := 0; i <= 10; i++ {
if i % 2 == 0 {
ch1 <- i
} else {
ch2 <- i
}
}
close(ch1)
close(ch2)
}
更多关于Golang中channel的顺序问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
5 回复
但是为什么我不能先读取第一个通道的值,然后再开始读取第二个通道呢?为什么必须保持顺序?我还是有点困惑……
你可以以任意顺序读取它们,不过你使用的是无缓冲通道,这意味着你的“send”协程会“休眠”,直到你从该通道读取了值。
如果你使用缓冲通道,效果会更好。
您可以按任意顺序读取,但要能够从通道读取,您需要先向其写入数据。
当前您有一个 goroutine 向两个通道中的一个写入数据。由于这些通道是无缓冲的,该 goroutine 在当前读取操作完成之前不会向另一个通道写入数据。
当您尝试首先从尚未写入数据的通道读取时,读取器也会阻塞,直到通道上有数据为止。
调度器识别出有两个 goroutine 都在等待解除阻塞。调度器会取消程序,因为它知道这两个 goroutine 的需求都无法得到满足。
在Go语言中,通道(channel)的发送和接收操作是顺序保证的,但多个通道之间的接收顺序取决于goroutine调度和通道状态。你的代码存在两个关键问题:
- 通道关闭后继续接收:当通道关闭后,从该通道接收会立即返回零值,导致重复读取
- 通道间顺序不确定:多个通道的接收顺序由运行时调度决定
这是修正后的示例,展示如何按任意顺序从不同通道接收:
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go send(ch1, ch2)
// 使用select实现任意顺序接收
for i := 0; i < 11; i++ {
select {
case v, ok := <-ch1:
if ok {
fmt.Printf("从ch1接收: %d\n", v)
}
case v, ok := <-ch2:
if ok {
fmt.Printf("从ch2接收: %d\n", v)
}
}
}
}
func send(ch1, ch2 chan<- int) {
for i := 0; i <= 10; i++ {
if i%2 == 0 {
ch1 <- i
time.Sleep(100 * time.Millisecond) // 模拟处理延迟
} else {
ch2 <- i
time.Sleep(50 * time.Millisecond) // 模拟处理延迟
}
}
close(ch1)
close(ch2)
}
输出顺序可能为:
从ch2接收: 1
从ch1接收: 0
从ch2接收: 3
从ch1接收: 2
从ch2接收: 5
从ch1接收: 4
...
如果要实现完全任意的接收顺序,可以使用带缓冲的通道和select:
func main() {
ch1 := make(chan int, 10)
ch2 := make(chan int, 10)
go send(ch1, ch2)
// 随机顺序接收
for {
select {
case v, ok := <-ch1:
if !ok {
ch1 = nil // 设置为nil后select将忽略此case
continue
}
fmt.Printf("从ch1接收: %d\n", v)
case v, ok := <-ch2:
if !ok {
ch2 = nil
continue
}
fmt.Printf("从ch2接收: %d\n", v)
default:
if ch1 == nil && ch2 == nil {
return
}
}
}
}
关键点:
- 单个通道保证FIFO顺序
- 多个通道间使用
select可实现非确定性的接收顺序 - 通道关闭后需处理零值问题
- 带缓冲通道允许发送和接收解耦

