Channel操作 #
一、发送操作 #
1.1 基本发送 #
go
ch := make(chan int)
ch <- 42
1.2 阻塞特性 #
go
func main() {
ch := make(chan int)
go func() {
time.Sleep(time.Second)
<-ch // 接收
}()
ch <- 1 // 阻塞直到被接收
fmt.Println("Sent")
}
1.3 缓冲发送 #
go
ch := make(chan int, 2)
ch <- 1 // 不阻塞
ch <- 2 // 不阻塞
// ch <- 3 // 阻塞
二、接收操作 #
2.1 基本接收 #
go
v := <-ch
2.2 检查是否关闭 #
go
v, ok := <-ch
if !ok {
fmt.Println("Channel closed")
}
2.3 阻塞接收 #
go
func main() {
ch := make(chan int)
go func() {
time.Sleep(time.Second)
ch <- 1
}()
v := <-ch // 阻塞直到有数据
fmt.Println(v)
}
2.4 非阻塞接收 #
go
select {
case v := <-ch:
fmt.Println(v)
default:
fmt.Println("No data")
}
三、关闭操作 #
3.1 close函数 #
go
ch := make(chan int)
close(ch)
3.2 关闭后的行为 #
go
ch := make(chan int, 2)
ch <- 1
ch <- 2
close(ch)
fmt.Println(<-ch) // 1
fmt.Println(<-ch) // 2
fmt.Println(<-ch) // 0(零值)
3.3 检测关闭 #
go
for {
v, ok := <-ch
if !ok {
break
}
fmt.Println(v)
}
3.4 range遍历 #
go
for v := range ch {
fmt.Println(v)
}
四、缓冲通道操作 #
4.1 容量管理 #
go
ch := make(chan int, 3)
fmt.Println(cap(ch)) // 3
fmt.Println(len(ch)) // 0
ch <- 1
fmt.Println(len(ch)) // 1
4.2 满与空 #
go
func isFull(ch chan int) bool {
return len(ch) == cap(ch)
}
func isEmpty(ch chan int) bool {
return len(ch) == 0
}
4.3 批量处理 #
go
func batchProcess(ch chan int, batchSize int) []int {
batch := make([]int, 0, batchSize)
for i := 0; i < batchSize; i++ {
select {
case v := <-ch:
batch = append(batch, v)
default:
return batch
}
}
return batch
}
五、单向通道操作 #
5.1 只发送 #
go
func sender(ch chan<- int) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
}
5.2 只接收 #
go
func receiver(ch <-chan int) {
for v := range ch {
fmt.Println(v)
}
}
5.3 API设计 #
go
type Queue struct {
ch chan int
}
func (q *Queue) Send() chan<- int {
return q.ch
}
func (q *Queue) Receive() <-chan int {
return q.ch
}
六、实际应用 #
6.1 限流器 #
go
func rateLimiter(limit int) chan struct{} {
ch := make(chan struct{}, limit)
for i := 0; i < limit; i++ {
ch <- struct{}{}
}
return ch
}
func main() {
limiter := rateLimiter(10)
for i := 0; i < 100; i++ {
<-limiter // 获取令牌
go func() {
defer func() { limiter <- struct{}{} }() // 归还令牌
// 处理请求
}()
}
}
6.2 超时控制 #
go
func withTimeout(ch <-chan int, timeout time.Duration) (int, error) {
select {
case v := <-ch:
return v, nil
case <-time.After(timeout):
return 0, errors.New("timeout")
}
}
6.3 广播 #
go
func broadcast(msg string, subscribers []chan string) {
for _, ch := range subscribers {
select {
case ch <- msg:
default:
}
}
}
6.4 管道 #
go
func pipeline() {
ch1 := make(chan int)
ch2 := make(chan int)
go func() {
for i := 0; i < 10; i++ {
ch1 <- i
}
close(ch1)
}()
go func() {
for v := range ch1 {
ch2 <- v * 2
}
close(ch2)
}()
for v := range ch2 {
fmt.Println(v)
}
}
七、常见模式 #
7.1 done通道 #
go
func worker(done chan struct{}) {
defer close(done)
// 工作
}
func main() {
done := make(chan struct{})
go worker(done)
<-done
}
7.2 结果通道 #
go
func compute(n int, results chan<- int) {
results <- n * n
}
func main() {
results := make(chan int, 10)
for i := 0; i < 10; i++ {
go compute(i, results)
}
for i := 0; i < 10; i++ {
fmt.Println(<-results)
}
}
7.3 取消通道 #
go
func worker(cancel <-chan struct{}) {
for {
select {
case <-cancel:
return
default:
// 工作
}
}
}
八、错误处理 #
8.1 向关闭通道发送 #
go
func safeSend(ch chan int, v int) error {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered:", r)
}
}()
ch <- v
return nil
}
8.2 关闭已关闭通道 #
go
func safeClose(ch chan int) {
select {
case <-ch:
// 已关闭
default:
close(ch)
}
}
九、最佳实践 #
9.1 明确关闭责任 #
go
func producer(ch chan int) {
defer close(ch) // 生产者关闭
// ...
}
9.2 使用select非阻塞 #
go
select {
case ch <- v:
// 发送成功
default:
// 处理缓冲满
}
9.3 合理设置缓冲大小 #
go
ch := make(chan int, runtime.NumCPU()*10)
十、总结 #
Channel操作要点:
| 操作 | 说明 |
|---|---|
| 发送 | ch <- v |
| 接收 | v := <-ch |
| 关闭 | close(ch) |
| 遍历 | for v := range ch |
关键点:
- 阻塞特性:理解发送和接收的阻塞行为
- 缓冲通道:提高性能,减少阻塞
- 关闭检测:使用ok值或range检测关闭
- 单向通道:提高类型安全性
- 错误处理:处理向关闭通道发送的情况
准备好学习Select语句了吗?让我们进入下一章!
最后更新:2026-03-26