likes
comments
collection
share

go panic 与 throw 的区别

作者站长头像
站长
· 阅读数 39

个人主页:二郎腿 (erlangtui.top)

一、基本介绍

  • panic 和 throw 都是 go 中抛出异常的内置函数,throw 常见于源码中,用户不能单独使用,panic 可以被用户单独使用,抛出异常时会中断当前程序;

二、panic

  • panic 是 go 语言中一个内置函数,用于终止当前 goroutine 并报告相关错误信息,panic 之后非 defer 的函数都无法执行;
  • 在 go 源代码中,常见的有数组内存越界、空指针、关闭一个 nil 管道等,都会发生 panic,用户也可以自行调用 panic 函数;
  • panic 是一种可以恢复的异常,可以通过 recover 函数捕获最近的一个 panic,并继续执行正常的流程,但是 recover 函数只能在 defer 函数中使用,并且只能 recover 当前 goroutine 的 panic,recover 捕获 panic 后,从捕获后的地方开始继续执行,panic 到 recover 之间的代码不会被执行
  • 使用 panicrecover 的基本流程如下:
func main() {
    defer func() {
        if err := recover(); err != nil {
            // 捕获了 panic,进行一些日志打印或报警
            fmt.Println("发生了 panic:", err)
        }
    }()
    
    // 模拟发生 panic
    panic("发生了一个错误")
    
    // 这行代码不会被执行
    fmt.Println("这行代码不会被执行")
}
// output: 发生了 panic: 发生了一个错误
  • 当在 defer 函数值中也发生了 panic,recover 只能捕获最近的一个,如下:
func main() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("recover ", err)
		}
	}()

	defer func() {
		panic("aaa")
	}()

	panic("bbb")
}
// output: recover  aaa

三、throw

  • throw 是 go 源码中一个函数,无法被用户调用,用于退出整个程序,并打印相应的 fatal msg;
  • go 语言认为这是无法动态修复的崩溃,所以不能通过 recover 来捕获
  • 例如源码中,阻塞等待一个 nil 管道、解锁一个未加锁的锁、并发读写 map 等,都会通过 throw 抛出崩溃;
func main() {
  var c chan int
  select {
  case c <- 1: // fatal error: all goroutines are asleep - deadlock!
  }
}
func main() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("recovering: ", err)
			return
		}
		fmt.Println("after recover")
	}()
	var m sync.Mutex
	m.Unlock()// fatal: sync: unlock of unlocked mutex
}
func main() {
  m := make(map[int]int)
  wg := sync.WaitGroup{}
  wg.Add(2)
  go func(w *sync.WaitGroup) {
    defer w.Done()
    for {
      m[1] = 2
    }
  }(&wg)
  go func(w *sync.WaitGroup) {
    defer w.Done()
    for {
      m[1] = 3
    }
  }(&wg)
  // fatal error: concurrent map writes
  wg.Wait()
}

三、总结

  • panic 抛出的异常能够在同一个 goroutine 被用户通过 defer 中的 recover 捕获,并继续 panic 之后的逻辑,用户也可以在业务逻辑中自行 panic 和 recover;
  • throw 抛出的崩溃无法通过 recover 的方式捕获,go 语言认为这是不应该恢复或是无法恢复的异常

参考文章 [1] panic 捕获和 throw 崩溃

转载自:https://juejin.cn/post/7387303384082792475
评论
请登录