go语言之无缓冲通道

Go 语言中的通道(channel)是用于协程间通信的核心工具。它有两种形式:无缓冲通道有缓冲通道


🌱 什么是通道(channel)?

在 Go 中,通道用于在 goroutine 之间传递数据。它就像一个传送带,一个 goroutine 把数据“放上去”,另一个 goroutine 把它“取下来”。


⚙️ 无缓冲通道(unbuffered channel)

✅ 特点:

  • 发送和接收必须同步进行。
  • 如果发送时没有接收方在等着,发送就会阻塞(卡住),直到接收方出现。
  • 更适合用于协程同步

🎯 比喻:

像两个人面对面递纸条,递的人不能走,直到接的人把纸条接过去。

🔧 示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import (
"fmt"
)

func main() {
ch := make(chan string) // 无缓冲通道

go func() {
ch <- "hello from goroutine" // 会阻塞直到 main() 接收
}()

msg := <-ch // 接收到消息后,上面的发送才完成
fmt.Println(msg)
}

⚙️ 有缓冲通道(buffered channel)

✅ 特点:

  • 允许指定缓冲大小
  • 发送操作在缓冲未满时不会阻塞。
  • 接收操作在缓冲非空时不会阻塞。
  • 适用于解耦发送者和接收者速度不同的场景。

🎯 比喻:

像一个邮箱,有多个格子可以放纸条。你可以先投进去,只要格子没满。

🔧 示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import (
"fmt"
)

func main() {
ch := make(chan string, 2) // 有缓冲通道,容量为2

ch <- "message 1" // ✅ 不阻塞
ch <- "message 2" // ✅ 不阻塞
// ch <- "message 3" // ❌ 超出缓冲,会阻塞,除非有接收

fmt.Println(<-ch) // 输出 message 1
fmt.Println(<-ch) // 输出 message 2
}

🧠 总结对比

特性 无缓冲通道 有缓冲通道
阻塞行为 发送和接收必须同步 缓冲满才阻塞发送,空才阻塞接收
是否适合同步 ✅ 是 ❌ 不直接适合
是否适合解耦速度 ❌ 否 ✅ 是
使用难度 稍高,容易死锁 相对灵活,但容易忘记接收