新手使用 go channel 需要注意的问题

本文探讨了Go语言中channel使用时常见的问题,包括阻塞、panic和内存泄漏,并提出了解决方案。重点讲解了何时关闭channel,如何判断channel是否关闭,以及如何优雅地关闭channel,以避免重复关闭和关闭后发送导致的panic。文章总结了四种关闭channel的情况,并提供了相应的策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

go channel 的应用可以说满是知识点,算是 golang 中的一个难点。新手使用时只要稍一不谨慎,就会造成各种问题。比如阻塞、panic、内存泄漏。接下来我将通过代码详细阐述这些问题及其解决方案。

目录

  • channel 为什么阻塞了?
  • 什么情况下关闭 channel 会造成 panic ?
  • 有没有必要关闭 channel?不关闭又如何?
  • 如何判断 channel 是否关闭?
  • 如何优雅地关闭 channel ?

channel 为什么阻塞了?

【知识点】go channel 如果没有设置缓冲队列,无论读取还是写入,都会阻塞。

如下代码所示:

func TestBlocking(t *testing.T) {
   
   errCh := make(chan error) // 1
   fmt.Println("make(chan error)")
   errCh <- errors.New("chan error") // 2
   fmt.Println("finish", <-errCh)
   
   // Output: 
   // make(chan error)
}

上述代码会一直阻塞。因为 1 处创建了一个无缓存队列的 channel,所以代码一直阻塞在 2 处。一种解决方案是创建 channel 时使用缓冲队列(如将 1 处代码替换为 errCh := make(chan error, 1));一种是使用 go routine 进行发送或读取操作,以防止阻塞(如下代码所示)。

func TestWithoutBlocking(t *testing.T) {
   
   errCh := make(chan error) 
   fmt.Println("make(chan error)")
   go func() {
    errCh <- errors.New("chan error") }
   fmt.Println("finish", <-errCh)
}

什么情况下关闭 channel 会造成 panic ?

先看示例:

// 1.未初始化时关闭
func TestCloseNilChan(t *testing.T) {
   
   var errCh chan error
   close(errCh)
   
   // Output:
   // panic: close of nil channel
}

// 2.重复关闭
func TestRepeatClosingChan(t *testing.T) {
   
   errCh := make(chan error)
   var wg sync.WaitGroup
   wg.Add(1)

   go func() {
   
      defer wg.Done()
      close(errCh)
      close(errCh)
   }()

   wg.Wait()
   
   // Output:
   // panic: close of closed channel
}

// 3.关闭后发送
func TestSendOnClosingChan(t *testing.T) {
   
   errCh := make(chan error)
   var wg sync.WaitGroup
   wg.Add(1)

   go func() {
   
      defer wg.Done()
      close(errCh)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值