1. 单向通道使用场景及代码示例
- 使用场景:单向通道用于限制数据流动方向,比如只能发送(
chan<-
)或只能接收(<-chan
)。常用于封装一个模块,只允许特定方向的数据操作,增强代码安全性和可读性。例如在生产者 - 消费者模型中,生产者向只能发送的通道发送数据,消费者从只能接收的通道读取数据。
- 代码示例:
package main
import (
"fmt"
)
// 生产者函数,向只能发送的通道发送数据
func producer(ch chan<- int) {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)
}
// 消费者函数,从只能接收的通道读取数据
func consumer(ch <-chan int) {
for val := range ch {
fmt.Println("Received:", val)
}
}
func main() {
ch := make(chan int)
go producer(ch)
consumer(ch)
}
2. 阻塞与非阻塞发送、接收的区别及实现
- 阻塞发送:
- 区别:当向通道发送数据时,如果通道已满(对于有缓冲通道)或没有接收者(对于无缓冲通道),发送操作会阻塞当前 goroutine,直到有接收者从通道接收数据(无缓冲通道)或通道有空闲空间(有缓冲通道)。
- 实现:
package main
import (
"fmt"
)
func main() {
ch := make(chan int, 1)
ch <- 1
fmt.Println("Sent 1")
// 这里如果没有接收操作,下一行发送操作会阻塞
ch <- 2
fmt.Println("Sent 2")
}
- 非阻塞发送:
- 区别:非阻塞发送不会阻塞当前 goroutine。如果通道已满(对于有缓冲通道)或没有接收者(对于无缓冲通道),发送操作会立即失败并返回。
- 实现:通过使用
select
语句结合 default
分支实现。
package main
import (
"fmt"
)
func main() {
ch := make(chan int, 1)
ch <- 1
select {
case ch <- 2:
fmt.Println("Sent 2")
default:
fmt.Println("Send operation failed")
}
}
- 阻塞接收:
- 区别:当从通道接收数据时,如果通道为空(对于有缓冲通道)或没有发送者(对于无缓冲通道),接收操作会阻塞当前 goroutine,直到有发送者向通道发送数据。
- 实现:
package main
import (
"fmt"
)
func main() {
ch := make(chan int)
go func() {
ch <- 1
}()
val := <-ch
fmt.Println("Received:", val)
}
- 非阻塞接收:
- 区别:非阻塞接收不会阻塞当前 goroutine。如果通道为空(对于有缓冲通道)或没有发送者(对于无缓冲通道),接收操作会立即返回零值(如果通道类型是基本类型)和一个表示是否成功接收到数据的布尔值。
- 实现:同样通过
select
语句结合 default
分支实现。
package main
import (
"fmt"
)
func main() {
ch := make(chan int)
select {
case val := <-ch:
fmt.Println("Received:", val)
default:
fmt.Println("Receive operation failed")
}
}