Golangで別のgoroutineで起こったpanicではdeferが実行されない
Go言語ではdefer文を使うことにより、関数が終了する際に必ず実行されるような処理を書くことができます。
これにより内部でpanicが起こったりした、通常とは違う処理をした場合でも、ファイルリソースなどの解放を確実に行うことができます、しかしいつも必ずというわけではないようです。たとえば別のgoroutineで起こったpanicにより実行が中断された場合、deferは実行されないようです、以下のようなコードで挙動の違いを確認できます。
問題が無いパターン(deferが実行され、panicがrecoverで補足できるパターン)
package main import ( "fmt" "time" ) func main() { defer func() { fmt.Println("defer!") if err := recover(); err != nil { fmt.Println("Err!") } }() func() { time.Sleep(time.Second) panic("panic!") }() time.Sleep(time.Second * 10) }
defer! Err!
deferが実行されないパターン(16行目でgoroutineを立てている)
package main import ( "fmt" "time" ) func main() { defer func() { fmt.Println("defer!") if err := recover(); err != nil { fmt.Println("Err!") } }() go func() { time.Sleep(time.Second) panic("panic!") }() time.Sleep(time.Second * 10) }
panic: panic! goroutine 5 [running]: panic(0x4b8e00, 0xc820068000) /usr/local/go/src/runtime/panic.go:464 +0x3e6 main.main.func2() /home/tsr/git/tmp/main.go:18 +0x72 created by main.main /home/tsr/git/tmp/main.go:19 +0x48 exit status 2
よく考えると納得の仕様のような気がしますが、軽くググってこれについて触れている記事などが見当たらなかったので書きました。
Copyright (C) 2016 tSU-RooT, Permission is granted to copy, distribute and/or modify this text. Unless otherwise noted, the text of this page is Dual licensed under a "Creative Commons Attribution 4.0(or any later version) International License", OR the "GNU Free Documentation License, Version 1.3(or any later version) published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts".