【笔记】Go语言的管道

前言

Go语言的管道(通信)channel学习笔记

管道的特点

  • 管道的本质是一种队列数据类型,数据是先进先出的
  • 管道是线程安全的,多协程goroutine访问时无需加锁
  • 管道定义时需要指定所存储数据的数据类型

声明一个管道

可读写管道

1
var 管道名 chan 数据类型

只读管道

1
var 管道名 chan<- 数据类型

只写管道

1
var 管道名 <-chan 数据类型

定义一个管道

  • 管道是引用类型数据,必须初始化才能写入数据
  • 管道变量实质上是一个指针,这个指针指向的是一个管道的真实地址
  • 管道的容量不能自动增长

有缓冲的管道

  • 有缓冲的管道是异步的,可以边发送数据边读取数据
1
var 管道名 chan 数据类型 = make(chan 数据类型, 缓冲区大小)

无缓冲的管道

  • 无缓冲的管道是同步的,在没有读取之前不能再次发送数据
  • 无缓冲的管道缓冲区大小为0
1
var 管道名 chan 数据类型 = make(chan 数据类型)

管道的数据发送与接收

  • 同一管道中,数据的发送与发送、接收与接收之前是互斥的

向管道发送数据

1
管道名 <- 数据

从管道读取数据

不接收读取的数据

1
<-管道名

接收读取的数据

1
变量名 = <-管道名

判断是否读取成功

ok:读取成功返回true,读取失败返回false,读取失败说明管道已关闭

1
_, ok = <-管道名

获取管道长度

1
len(管道名)

获取管道容量

1
cap(管道名)

关闭管道

  • 关闭管道后,不能再向管道中写入数据了,但是可以继续从管道中读取数据
1
close(管道名)

遍历管道

  • 遍历管道之前最好先关闭管道
  • 先发送数据再读取数据
    • 如果发送数据的个数大于或等于读取数据的个数,无论管道是否正常关闭,都可以正常读取数据
    • 如果发送数据的个数小于读取数据的个数
      • 如果管道已经关闭,则未超出部分能正常读取,超出部分的读取会得到数据类型的零值
      • 如果管道没有关闭,则未超出部分能正常读取,超出部分的读取会报deadlock死锁错误
        • 如果此时使用for...range的方式遍历管道,一定会报deadlock死锁错误
1
2
3
4
close(管道名)
for value := range 管道名 {
...
}

select关键字

  • 如果管道不清楚什么时候关,可以使用select关键字防止阻塞
  • select中的case必须是channel操作
  • select中的default必须始终是可以运行的
  • 如果select中有多个可以执行的case子句,select会随机选择一个可以执行的case子句执行,其他的case子句不会被执行
  • 如果select中有default子句,当所有case都不能执行时,会跳到default中执行
  • 如果select中没有default子句,当所有的case都不能执行时,会阻塞并发生死锁
1
2
3
4
5
6
select {
case value := <-管道名:
...
default:
...
}

无限循环

1
2
3
4
5
6
7
8
label:
select {
case value := <-管道名:
...
default:
break label
}
}

完成

参考文献

哔哩哔哩——尚硅谷
哔哩哔哩——郭宏志-老郭
哔哩哔哩——go圈里最会写js的奇淼