关于Panic使用的俩个易错点

在日常开发中一不小心程序就会出现panic,如果没有注册recoverpanic会直接中断程序后面的逻辑,使用不当会带来巨大的隐患。下面小老虎就来介绍俩点关于panic的常见错误!

一、Panic与Recover

在并发问题中,我们常常使用读写锁来保证并发的安全性。在内存泄漏的七种场景中我们提到锁的使用不当,会使得groutine因获取不到锁,而导致内存泄漏。下面以超超和婷婷获取电视使用权为例。

定义电视结构体并提供注册和获取当前使用者的方法

type Television struct {

  belong string

  sync.RWMutex

}func (m *Television) set(name string) {

  m.Lock()

  m.belong = name

  m.Unlock()

}func (m *Television) get() string {

  m.RLock()

  user := m.belong

  m.RUnlock()

  return user

}

主进程中用户并发获取电视机使用权

func main() {

  users := []string{"chaochao", "tingting"}

  tv := &Television{}

  w := sync.WaitGroup{}

  usersLen := len(users)

​

  w.Add(usersLen)

  for i := 0; i < usersLen; i++ {

  go func(user string) {

    tv.set(user)

    w.Done()

  }(users[i])

  }

  w.Wait()

  fmt.Println("TV user is", tv.get())

}

输出结果

TV user is tingting

看似没有任何问题,如果get方法和set方法再复杂一些,中间不小心出了panic,会怎么样呢?

func (m *Television) set(name string) {

  m.Lock()

  m.belong = name

 //模拟出现的panic

  panic("setErr")

  m.Unlock()

}

那么整个程序都会崩溃,线上如果出现这样的问题,基本属于中大奖了!因此需要注册一个deferrecover这个panic,使得程序能够继续运行。

func main() {

  users := []string{"chaochao", "tingting"}

  tv := &Television{}

  w := sync.WaitGroup{}

  usersLen := len(users)

​

  w.Add(usersLen)

  for i := 0; i < usersLen; i++ {

  go func(user string) {

 //获取处理异常

    defer func() {

      if err := recover(); err != nil {

        fmt.Println("err:", err)

      }

    }()

    tv.set(user)

    w.Done()

  }(users[i])

  }

  w.Wait()

  fmt.Println("TV user is", tv.get())

}

看似程序到这没有问题了,但是真是如此吗?

二、内存泄漏

set方法中,panic之前有一个获取锁的操作,panic之后set方法直接退出了,并没有释放锁。这时其他协程在尝试获取锁时就会失败,从而造成Goroutine的泄漏。

image-20220226153642102因此锁的释放最好在lock后注册一个defer进行释放。

type Television struct {

  belong string

  sync.RWMutex

}func (m *Television) set(name string) {

  m.Lock()

 defer  m.Unlock()

  m.belong = name

}func (m *Television) get() string {

  m.RLock()

 defer m.RUnlock()

  user := m.belong

  return user

}
三、总结

本文介绍了panicrecover的使用场景,recover通常放在defer中防止panic中断程序给线上带来巨大的影响。紧接着介绍了锁的释放最好也放在defer中,防止painic时未释放锁导致其他协程未拿到锁而导致内存泄漏。关于painic更多的注意事项,欢迎小伙伴们在下方留言讨论呀!

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!