定义区别
- 非缓冲通道:也叫无缓冲通道,在创建时不指定缓冲区大小。定义格式为
make(chan Type)
,例如 ch := make(chan int)
。这种通道在发送和接收操作时,发送方和接收方必须同时准备好,它们之间是同步的。
- 缓冲通道:创建时指定了缓冲区大小。定义格式为
make(chan Type, capacity)
,例如 ch := make(chan int, 5)
。缓冲区用于暂存数据,使得发送操作在缓冲区未满时不需要立即有接收方准备好。
特性区别
- 非缓冲通道:
- 数据传递是同步的,发送操作和接收操作会阻塞,直到双方都准备好。
- 保证收发数据的顺序性,先发送的数据先被接收。
- 缓冲通道:
- 发送操作在缓冲区未满时不会阻塞,接收操作在缓冲区非空时不会阻塞。
- 当缓冲区满时发送操作会阻塞,缓冲区空时接收操作会阻塞。
- 数据顺序性依赖于发送和接收操作的顺序,缓冲区只是暂存数据。
适用场景区别
- 非缓冲通道:
- 适用于需要确保数据同步传递的场景,比如在多个 goroutine 之间进行精确的同步操作,例如信号传递。
- 例如实现一个简单的信号同步,主 goroutine 等待子 goroutine 完成任务后再继续执行:
package main
import (
"fmt"
)
func main() {
done := make(chan struct{})
go func() {
// 模拟一些工作
fmt.Println("子 goroutine 工作中")
done <- struct{}{}
}()
<-done
fmt.Println("主 goroutine 继续执行")
}
- 缓冲通道:
- 适用于解耦发送方和接收方的场景,例如生产者 - 消费者模型,生产者可以持续向缓冲区发送数据,消费者从缓冲区消费数据,只要缓冲区有空间或有数据,它们就可以异步工作。
- 如下是简单的生产者 - 消费者示例:
package main
import (
"fmt"
)
func producer(ch chan int) {
for i := 0; i < 5; i++ {
ch <- i
fmt.Printf("生产者发送: %d\n", i)
}
close(ch)
}
func consumer(ch chan int) {
for num := range ch {
fmt.Printf("消费者接收: %d\n", num)
}
}
func main() {
ch := make(chan int, 3)
go producer(ch)
go consumer(ch)
select {}
}
创建示例
package main
import "fmt"
func main() {
// 创建非缓冲通道
unbufferedChan := make(chan int)
go func() {
unbufferedChan <- 42
}()
value := <-unbufferedChan
fmt.Println("接收到的值:", value)
}
package main
import "fmt"
func main() {
// 创建缓冲通道,缓冲区大小为 2
bufferedChan := make(chan int, 2)
bufferedChan <- 10
bufferedChan <- 20
fmt.Println("从缓冲通道接收:", <-bufferedChan)
fmt.Println("从缓冲通道接收:", <-bufferedChan)
}