Go-channel(管道)总结

特性

一个还未初始化的通道会被预置为nil(编译和运行时不会报错)

channel在使用时,需要使用make操作符,make会初始化通道,在内存中分配通道的空间。

引发panic的原因

关闭一个 nil 值 channel 会引发 panic。

package main
​
func main() {
  var ch chan struct{}
  close(ch)
}

关闭一个已关闭的 channel 会引发 panic。

package main
​
func main() {
  ch := make(chan struct{})
  close(ch)
  close(ch)
}

向一个已关闭的 channel 发送数据。

package main
​
func main() {
  ch := make(chan struct{})
  close(ch)
  ch <- struct{}{}
}

以上三种 channel 操作会引发 panic。 实际项目是很复杂的,一不小心,你就会忘了自己曾在哪一个 g 里关闭过 channel。

 

管道的读取

死锁

因为管道没有关闭 所以读取的时候 会一直阻塞当前读取 导致锁等待 造成死锁

package main

import "fmt"

func main() {
    ch := make(chan int, 8)
    ch <- 1
    ch <- 2
    //close(ch)
    fmt.Println(<-ch) //1
    fmt.Println(<-ch) //2
    //fmt.Println(<-ch)//
}

返回零值

当从关闭的管道读取不到数据时,会返回管道类型的默认值比如 int 会返回 0

package main

import "fmt"

func main() {
    ch := make(chan int, 8)
    ch <- 1
    ch <- 2
    close(ch)
    fmt.Println(<-ch) //1
    fmt.Println(<-ch) //2
    fmt.Println(<-ch) //0
}

 

判断管道是否关闭

接收值和布尔值判断:

在接收 channel 的值时,可以使用多重赋值的方式接收两个值,一个是接收到的值,另一个是表示 channel 是否关闭的布尔值。如果 channel 已关闭且没有待接收的值,那么接收操作会立即返回并产生一个默认值。通过检查布尔值,可以判断 channel 是否已关闭。例如:

value, ok := <-ch
if !ok {
    // channel 已关闭
}

使用 range 迭代:

可以使用 range 关键字来迭代 channel,当 channel 被关闭时,迭代会自动终止。可以通过检查循环中的布尔值来判断 channel 是否已关闭。例如:

for value := range ch {
    // 迭代 channel 的值
}
// channel 已关闭

此外,还可以使用 select 语句结合 default 分支来判断 channel 是否关闭。当一个已关闭的 channel 没有待接收的值时,通过 select 语句的 default 分支可以立即执行对应的逻辑。

 

 

 

 

 
posted @ 2023-06-21 22:13  GJH-  阅读(18)  评论(0编辑  收藏  举报