Golang中关于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的泄漏。

Golang中关于Panic的俩点注意事项_第1张图片因此锁的释放最好在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更多的注意事项,欢迎小伙伴们在下方留言讨论呀!

你可能感兴趣的:(golang异常处理)