一:先打个比方:快递柜和当面签收

想象你要给朋友送一个礼物:

无缓冲 channel = 当面签收(必须同时在场)

你拿着礼物站在朋友家门口,必须等他开门出来,你亲手把礼物交到他手上,你才能离开。

  • 如果他不在家,你就一直等着(阻塞)

  • 他必须亲自来拿,你们必须同时在场

有缓冲 channel = 快递柜(不用同时在场)

你把礼物放进快递柜,然后就可以走了。朋友什么时候有空,自己来取。

  • 如果柜子满了,你就放不进去了,得等着(阻塞)

  • 如果柜子是空的,朋友取了也没东西,也得等着

二:代码示例(超级简单版)

无缓冲:必须同时准备好

package main

import "fmt"

func main() {
    // 创建一个无缓冲 channel(像当面签收)
    ch := make(chan string)
    
    // 朋友在另一个房间等着收礼物
    go func() {
        gift := <-ch  // 朋友等着收礼物
        fmt.Println("朋友收到:", gift)
    }()
    
    // 你送礼物(必须等朋友准备好)
    fmt.Println("你送出礼物")
    ch <- "一个蛋糕"
    fmt.Println("你离开了")
}

输出:

你送出礼物
朋友收到: 一个蛋糕
你离开了

关键:你送礼物的时候,如果朋友还没准备好,你会一直等。

有缓冲:可以放快递柜

package main

import "fmt"

func main() {
    // 创建一个有缓冲 channel,柜子能放2个礼物
    ch := make(chan string, 2)
    
    // 你直接往柜子里放礼物,不用等朋友
    fmt.Println("你放第一个礼物")
    ch <- "蛋糕"
    
    fmt.Println("你放第二个礼物")
    ch <- "鲜花"
    
    // 柜子满了,再放就要等了
    // ch <- "第三个"  // 这行会报错(死锁)
    
    // 朋友有空了来取
    fmt.Println("朋友取到:", <-ch)
    fmt.Println("朋友取到:", <-ch)
}

输出:

你放第一个礼物
你放第二个礼物
朋友取到: 蛋糕
朋友取到: 鲜花

关键:你不用等朋友,直接放进去就走,他晚点来拿。

三:一张图看懂区别

无缓冲 channel(当面给):
你 -----(等)-----> 朋友(必须同时)
      (直接交接)
      
有缓冲 channel(快递柜):
你 --(放)--> [柜子] --(取)--> 朋友
            (有缓冲区)

四:什么时候用哪个?

场景 用哪种 为什么
通知朋友"我到了" 无缓冲 必须确认他听到了
做任务时限制同时人数 有缓冲 放令牌到柜子里,用完放回
生产蛋糕,消费者慢慢吃 有缓冲 生产快消费慢,用柜子缓冲
两件事必须同步完成 无缓冲 必须手拉手一起做

五:最容易犯的错

错误1:无缓冲时没人接收就发送

ch := make(chan int)
ch <- 5  // 死锁!因为没人接收

就像你拿着礼物站在门口,但朋友根本不在家,你就永远等下去。

错误2:有缓冲时忘记检查容量

ch := make(chan int, 1)  // 只能放1个
ch <- 10
ch <- 20  // 死锁!柜子满了

就像快递柜只有一个格子,你想放两个进去,第二个放不进去,只能干等。

六:最简记忆法

无缓冲 = 必须两个人同时在线,才能发消息
有缓冲 = 可以发消息到"收件箱",对方有空再看

更多推荐