宕机(panic)——程序终止运行
# 2. 宕机(panic)——程序终止运行
# 介绍
Go语言的类型系统会在编译时捕获很多错误,但有些错误只能在运行时检查,如数组访问越界、空指针引用等,这些运行时错误会引起宕机。
宕机不是一件很好的事情,可能造成体验停止、服务中断,就像没有人希望在取钱时遇到 ATM 机蓝屏一样,但是,如果在损失发生时,程序没有因为宕机而停止,那么用户将会付出更大的代价,这种代价可以是金钱、时间甚至生命,因此,宕机有时也是一种合理的止损方法。
一般而言,当宕机发生时,程序会中断运行,并立即执行在该 goroutine(可以先理解成线程)中被延迟的函数(defer 机制),随后,程序崩溃并输出日志信息,日志信息包括 panic value 和函数调用的堆栈跟踪信息,panic value 通常是某种错误信息。
对于每个 goroutine,日志信息中都会有与之相对的,发生 panic 时的函数调用堆栈跟踪信息,通常,我们不需要再次运行程序去定位问题,日志信息已经提供了足够的诊断依据,因此,在我们填写问题报告时,一般会将宕机和日志信息一并记录。
虽然Go语言的 panic 机制类似于其他语言的异常,但 panic 的适用场景有一些不同,由于 panic 会引起程序的崩溃,因此 panic 一般用于严重错误,如程序内部的逻辑不一致。任何崩溃都表明了我们的代码中可能存在漏洞,所以对于大部分漏洞,我们应该使用Go语言提供的错误机制,而不是 panic。
内建的函数 panic() 就可以造成崩溃,panic() 的声明如下
func panic(v interface{}) //panic() 的参数可以是任意类型的。
# 手动触发宕机
Go语言可以在程序中手动触发宕机,让程序崩溃,这样开发者可以及时地发现错误,同时减少可能的损失。
Go语言程序在宕机时,会将堆栈和 goroutine 信息输出到控制台,所以宕机也可以方便地知晓发生错误的位置,那么我们要如何触发宕机呢,示例代码如下所示:
package main
func main() {
panic("xxx") // 手动触发宕机
}
/*
panic: xxx
goroutine 1 [running]:
main.main()
G:/GolangCode/my/golang-foundation/6. 异常处理/2. panic宕机.go:4 +0x27
*/
2
3
4
5
6
7
8
9
10
11
12
13
# 在宕机时触发延迟执行语句
当 panic() 触发的宕机发生时,panic() 后面的代码将不会被运行,但是在 panic() 函数前面已经运行过的 defer 语句依然会在宕机发生时发生作用
package main
import "fmt"
func main() {
defer fmt.Println("宕机后要做的事情1")
defer fmt.Println("宕机后要做的事情2")
panic("触发宕机") // 手动触发宕机
// 当 panic() 触发的宕机发生时,panic() 后面的代码将不会被运行,但是在 panic() 函数前面已经运行过的 defer 语句依然会在宕机发生时发生作用
}
/*
宕机后要做的事情2
宕机后要做的事情1
panic: 触发宕机
goroutine 1 [running]:
main.main()
G:/GolangCode/my/golang-foundation/6. 异常处理/2. panic宕机.go:8 +0xac
*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20