golang channel 的使用

清疚 2022-06-04 03:50 363阅读 0赞

本文对channel使用中的几个疑惑,以例子的形式加以说明。

普通channel

缺省情况下,发送和接收会一直阻塞着,直到另一方准备好.
例如:

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. var ch1 chan bool
  7. func main(){
  8. ch1 = make(chan bool)
  9. go reader()
  10. go writer()
  11. select {
  12. }
  13. }
  14. func writer() {
  15. time.Sleep(10*time.Second)
  16. for {
  17. ch1 <- true
  18. fmt.Println("write one ...")
  19. }
  20. }
  21. func reader() {
  22. for {
  23. select {
  24. case <-ch1:
  25. fmt.Println("read one ....")
  26. }
  27. time.Sleep(2*time.Second)
  28. }
  29. }

output:

$ ./chan1.exe
write one …
read one ….
read one ….
write one …
read one ….
write one …
read one ….
write one …

从执行结果看,reader卡住,直到writer sleep后就位,才继续执行。反之,让reader先睡眠,writer也会卡住,直到reader sleep后就位。

带buffer的channel

带buffer的channel可以减少阻塞,对一些需要只保持有限个执行过程的情景很有用。

例1:

  1. // reader wait, until writer begin to write.
  2. package main
  3. import (
  4. "fmt"
  5. "time"
  6. )
  7. var ch1 chan bool
  8. func main(){
  9. ch1 = make(chan bool, 1)
  10. go reader()
  11. go writer()
  12. select {
  13. }
  14. }
  15. func writer() {
  16. time.Sleep(10*time.Second)
  17. for {
  18. ch1 <- true
  19. fmt.Println("write one ...")
  20. }
  21. }
  22. func reader() {
  23. for {
  24. select {
  25. case <-ch1:
  26. fmt.Println("read one ....")
  27. }
  28. time.Sleep(2*time.Second)
  29. }
  30. }

这种情景中,先让writer睡眠,reader此时卡住,直到writer就位,也就是说,带buffer,如果没有数据写入,reader也是卡住的。

例2:

  1. // writer write one, then wait
  2. package main
  3. import (
  4. "fmt"
  5. "time"
  6. )
  7. var ch1 chan bool
  8. func main(){
  9. ch1 = make(chan bool, 1)
  10. go reader()
  11. go writer()
  12. select {
  13. }
  14. }
  15. func writer() {
  16. for {
  17. ch1 <- true
  18. fmt.Println("write one ...")
  19. }
  20. }
  21. func reader() {
  22. time.Sleep(10*time.Second)
  23. for {
  24. select {
  25. case <-ch1:
  26. fmt.Println("read one ....")
  27. }
  28. time.Sleep(2*time.Second)
  29. }
  30. }

如果先让reader睡眠,writer直接向channel写,可以看到writer可以写入一个数据,然后卡住,直到reader就位,才可以继续写。
也就是说,带一个buffer的channel,可以在reader就位前首先写入一个数据。

关闭channel

可以使用內建close关闭channel,例如,

  1. close(ch)
  • 当channel关闭后,继续写入会报:

    panic: send on closed channel

  • 如果从这个关闭的channel中读数据,不但可以读取出已发送的数据,还可以不断的读取零值。

如何判断channel已经关闭了?

  • 通过range读取
    channel关闭后for循环会跳出:

    for v := range chan {

    }

  • 通过i, ok := <-c
    可以查看Channel的状态,判断值是零值还是正常读取的值。
    如果ok是false,表示没有数据可读,并且channel已经关闭。

建议

  • 只有发送者去关闭channel,接收者不要去关闭channel。
    如果channel已经关闭,发送者会引起panic。
  • 通常情况下,没有必要关闭channel。

参考

http://colobu.com/2016/04/14/Golang-Channels/

发表评论

表情:
评论列表 (有 0 条评论,363人围观)

还没有评论,来说两句吧...

相关阅读

    相关 golangchannel超时

    基本语法 通道声明和初始化 我们可以通过`chan`关键字来声明通道类型变量 var ch chan int // 声明一个通道类型变量 ch,并且通道

    相关 golang channel 使用

    本文对channel使用中的几个疑惑,以例子的形式加以说明。 普通channel 缺省情况下,发送和接收会一直阻塞着,直到另一方准备好. 例如: pack

    相关 golangChannel

    Channel是Go中的一个核心类型,可以将其看成一个管道,通过它并发单元就可以发送或者接收数据进行通信(communication)。 `Do not communicat