主要分这几种情况:
1:main内协程在运行时,main 函数体内panic
package main
import ("errors"
"fmt"
"time")
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println("err:", err)
}
}()
go test()
time.Sleep(time.Second * 2)
panic(errors.New("main panic"))
fmt.Println("main out")
select {}
}
func test() {
for {
tm := time.NewTicker(time.Second)
select {
case <-tm.C:
fmt.Println("test out")
}
}
}
输出:
test out
err: main panic
结论:
main 内的 panic 会带着 main 内的协程一起崩溃。
2:main内协程在运行时,main 内函数panic,main 内函数无 recover
package main
import ("errors"
"fmt"
"time")
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println("err:", err)
}
}()
go test()
time.Sleep(time.Second * 2)
goPanic()
fmt.Println("main out")
select {}
}
func test() {
for {
tm := time.NewTicker(time.Second)
select {
case <-tm.C:
fmt.Println("test out")
}
}
}
func goPanic(){
panic(errors.New("goPanic panic"))
fmt.Println("goPanic out")
}
输出:
test out
err: goPanic panic
结论:
main 内函数的 panic 因为没有相应的recover处理,会带着 main 内的协程一起崩溃。
3:main内协程在运行时,main 内函数panic,main 内函数有 recover
package main
import ("errors"
"fmt"
"time")
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println("err:", err)
}
}()
go test()
time.Sleep(time.Second * 2)
goPanic()
fmt.Println("main out")
select {}
}
func test() {
for {
tm := time.NewTicker(time.Second)
select {
case <-tm.C:
fmt.Println("test out")
}
}
}
func goPanic(){
defer func() {
if err := recover(); err != nil {
fmt.Println(" goPanic err:", err)
}
}()
panic(errors.New("goPanic panic"))
fmt.Println("goPanic out")
}
输出:
test out
goPanic err: goPanic panic
main out
test out
test out
test out
...
结论:
main 内函数的 panic 因为有相应的recover处理,不会累及 main 内的其他协程和逻辑。
4:main内协程在运行时panic,协程无recover
package main
import ("errors"
"fmt"
"time")
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println("err:", err)
}
}()
go test()
time.Sleep(time.Second * 2)
fmt.Println("main out")
select {}
}
func test() {
tk := time.NewTicker(time.Second)
tm := time.NewTimer(2*time.Second)
for {
select {
case <-tk.C:
fmt.Println("test out")
case <-tm.C:
panic(errors.New("test panic"))
}
}
}
输出:
test out
test out
panic: test panic
goroutine 6 [running]:
main.test()
/code/main.go:31 +0x18b
created by main.main
/code/main.go:14 +0x5b
exit status 2
结论:
协程的 panic 会上报至 main,一起崩溃。
4:main内协程在运行时panic,协程有recover
package main
import ("errors"
"fmt"
"time")
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println("err:", err)
}
}()
go test()
time.Sleep(time.Second * 2)
fmt.Println("main out")
select {}
}
func test() {
defer func() {
if err := recover(); err != nil {
fmt.Println(" test err:", err)
}
}()
tk := time.NewTicker(time.Second)
tm := time.NewTimer(2*time.Second)
for {
select {
case <-tk.C:
fmt.Println("test out")
case <-tm.C:
panic(errors.New("test panic"))
}
}
}
输出:
test out
test out
test err: test panic
main out
结论:
协程的 panic会及时被 recover 处理, 不会上报至 main,其他运行照常。