Go语言channel备忘录

目录

  1. 无缓冲channel等价于缓冲大小为0的channel,而不是1
  2. 发送者和接收者哪些情况会阻塞
  3. close哪些情况会导致panic
  4. 如何优雅的关闭channel
  5. 当一个select中有多个channel满足可读时,谁被激活
  6. select with default
  7. 读取时获取第二个返回值,以此判断该channel是否被关闭
  8. close前写入的数据,接收者依然可以按顺序读取到
  9. 一个channel有多个接收者时,close channel会唤醒所有接收者
  10. 配合timer实现channel读取的超时机制
  11. 当channel只用做同步通知,不关心channel中传输的值时,可使用 chan struct{} 类型
  12. 单向channel类型的作用
  13. 可以make单向channel,但是这样做没有意义
  14. channel配合for range的简化写法
1. 无缓冲channel等价于缓冲大小为0的channel,而不是1
var ch chan int // ch == nil

// 创建无缓冲channel
ch := make(chan int) // ch != nil
// 等价于
// ch := make(chan int, 0)
// 不等价于
// ch := make(chan int, 1)

close(ch) // close执行后, ch != nil
2. 发送者和接收者哪些情况会阻塞
  • 往值为nil的channel发送数据: 永久阻塞
  • 从值为nil的channel读取数据: 永久阻塞
  • 无缓冲模式的发送者: 阻塞直到数据被接收者接收
  • 无缓冲模式的接收者: 无数据可读时,阻塞
  • 有缓冲模式的发送者: 当缓冲满时,阻塞
  • 有缓冲模式的接收者: 无数据可读时,阻塞
3. close哪些情况会导致panic
  1. close值为nil的channel
  2. close已经被close的channel
  3. 向已经被close的channel发送数据
4. 如何优雅的关闭channel

需要特别注意:

  1. 接收者关闭channel要小心,因为关闭后发送者继续发送会panic
  2. 当有多个发送者时,在一个发送者协程中关闭channel要小心,因为关闭后其他发送者继续发送会panic

复杂情况下的参考思路:

  1. channel的关闭并非必须的,只要channel对象不再被持有,垃圾回收器会清理它
  2. 可使用原子变量等同步原语保证close有且只有发生一次
  3. 除了传输数据的channel,可以再增加channel配合select使用,用于取消生产、消费
  4. 接收端也可以通过其他channel发出消息,反向通知发送端
5. 当一个select中有多个channel满足可读时,谁被激活

Go随机选取一个满足条件的case分支执行,而不是按代码顺序选取。

// 如下代码段,可能输出ch1,也可能输出ch2
ch1 := make(chan int, 8)
ch2 := make(chan int, 8)
ch1 <- 1
ch2 <- 1
select {
case <- ch1:
    fmt.Println("ch1")
case <- ch2:
    fmt.Println("ch2")
}
6. select with default

当select中的条件都不满足时,会立即执行default分支

// 如下代码段,会立即打印default
ch1 := make(chan int, 1)
ch2 := make(chan int)
select {
case <- ch1:
    fmt.Println("ch1")
case <- ch2:
    fmt.Println("ch2")
default:
    fmt.Println("default")
}
7. 读取时获取第二个返回值,以此判断该channel是否被关闭
v, ok := <- ch
// 当channel被关闭后,v为channel类型的零值,ok为false
8. close前写入的数据,接收者依然可以按顺序读取到
ch := make(chan int, 8)
ch <- 1
ch <- 2
ch <- 3
close(ch)

for {
    v, ok := <- ch
    fmt.Println(v, ok)
    if !ok {
        break
    }
}
// 以上代码段,将打印出如下结果:
// 1 true
// 2 true
// 3 true
// 0 false
9. 一个channel有多个接收者时,close channel会唤醒所有接收者
10. 配合timer实现channel读取的超时机制

但在高性能场景需要注意,参见: golang源码阅读之定时器以及避坑指南

11. 当channel只用做同步通知,不关心channel中传输的值时,可使用 chan struct{} 类型

好处是语意上更正确,代码可读性更高。

// 初始化
ch := make(chan struct{}, 1)

// 写入
ch <- chan struct{}{}
12. 单向channel类型的作用
// 比如Go系统库中Timer的实现,就使用了只读类型的channel,
// 目的是限制该channel在上层Timer对象只能读,不能写。这种限制是编译期的

// 提供给用户的Timer对象
type Timer struct {
    C <-chan Time // 只读类型
    r runtimeTimer
}

// 实际make的是chan Time类型
func NewTimer(d Duration) *Timer {
    c := make(chan Time, 1)
    t := &Timer{
        C: c, // chan Time转换成只读类型,后续通过Timer对象访问C数据成员的操作只能读,不能写
        r: runtimeTimer{
            when: when(d),
            f:    sendTime,
            arg:  c, // 将chan Time类型传递给底层runtimeTimer中使用,底层可以写
        },
    }
    startTimer(&t.r)
    return t
}

// 用户调用After时,返回只读类型的channel
func After(d Duration) <-chan Time {
    return NewTimer(d).C
}
13. 可以make单向channel,但是这样做没有意义
// 以下初始化了一个只写的channel是合法的,但是只能写,不能读,应该没有这种使用场景
ch := make(chan<- int, 4)
14. channel配合for range的简化写法
ch := make(chan int, 4)
ch <- 1
ch <- 2
close(ch)
for v := range ch {
    fmt.Println(v)
}
fmt.Println("< for")
// 以上代码段将打印如下结果
// 1
// 2
// < for

参考链接

备忘录类型文章,后续的修改会第一时间在我的个人站点更新,地址: https://pengrl.com/p/23102

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容