在 Go 语言中,channel 的发送和接收操作会根据其缓冲区的状态而阻塞或恢复。以下是详细说明:
1. 无缓冲 channel
-
发送操作:
- 阻塞:发送数据时会阻塞,直到有另一个 goroutine 从该 channel 接收数据。
-
接收操作:
- 阻塞:接收数据时会阻塞,直到有另一个 goroutine 向该 channel 发送数据。
2. 有缓冲 channel
-
发送操作:
- 阻塞:当缓冲区已满时,发送操作会阻塞,直到有空间可以发送数据。
- 恢复:当接收操作释放了空间(即接收数据),发送操作会恢复执行。
-
接收操作:
- 阻塞:当缓冲区为空时,接收操作会阻塞,直到有数据可以接收。
- 恢复:当发送操作添加了数据,接收操作会恢复执行。
示例代码
以下是一个示例,展示无缓冲和有缓冲 channel 的阻塞和恢复行为:
package main
import (
"fmt"
"time"
)
func main() {
// 无缓冲 channel 示例
ch1 := make(chan int)
go func() {
ch1 <- 1 // 发送数据,阻塞直到接收
fmt.Println("Sent 1")
}()
// 主 goroutine 等待一秒再接收
time.Sleep(1 * time.Second)
fmt.Println("Received:", <-ch1) // 接收数据,解除阻塞
// 有缓冲 channel 示例
ch2 := make(chan int, 2) // 缓冲区大小为 2
ch2 <- 1 // 不会阻塞
ch2 <- 2 // 也不会阻塞
go func() {
ch2 <- 3 // 这里会阻塞,直到有接收
fmt.Println("Sent 3")
}()
fmt.Println("Received from buffered channel:", <-ch2) // 接收,解除阻塞
fmt.Println("Received from buffered channel:", <-ch2) // 继续接收
time.Sleep(1 * time.Second) // 确保 goroutine 完成
}
总结
- 无缓冲 channel:发送和接收操作会相互阻塞,直到对方准备好。
- 有缓冲 channel:发送操作在缓冲区未满时不会阻塞;接收操作在缓冲区为空时会阻塞。