Go์์ ์ค์ํ๊ธฐ ์ฌ์ด ์ผ์ด์ค - defer, panic, recover
2์ค ์์ฝ
- recover ๋ deferํจ์์ ์ํด ์ง์ ์ ์ผ๋ก ํธ์ถ๋๋ฉด ์๋๋ค.
- panic์ ์ค๋จ์ํฌ ํจ์์ depth๊ฐ n์ด๋ผ๋ฉด recover๋ n+1 ์์ ํธ์ถ๋์ด์ผ ํ๋ค.
์ฐฉ๊ฐํ๊ธฐ ์ฌ์ด ์ผ์ด์ค
๋ค๋ฅธ ์ธ์ด์ try-catch๋ฌธ๊ณผ ๋น์ทํ๊ฒ go์์๋ defer, panic, recover ํจํด์ ์ด์ฉํด์ ๋ฐ์ํ๋ ์์ธ ์ํฉ์ ์ ์ด ํ ์ ์๋ค.
package main
import (
"fmt"
)
func main() {
defer a()
panic("panic!")
}
func a() {
r := recover()
fmt.Println("recoverd: ", r)
fmt.Println("a called")
}
recoverd: panic!
a called
Program exited.
๋ง์ฝ ์ง์ฐ ํธ์ถ ์ํฌ ํจ์๊ฐ recover์ธ์ ํ๋ ๋ ์๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์์ฑ ํ ์๋ ์๋ค.
package main
import (
"fmt"
)
func main() {
defer b()
defer a()
panic("panic!")
}
func a() {
r := recover()
fmt.Println("recoverd: ", r)
fmt.Println("a called")
}
func b() {
fmt.Println("b called")
}
recoverd: panic!
a called
b called
Program exited.
์ฌ๊ธฐ์ ๋ ๋์๊ฐ ์ฝ๋๋ฅผ ์ข ๋ ๊น๋ํ๊ฒ ์ ๋ํ๊ณ ์ถ์ด์ ์ต๋ช ํจ์๋ก a()์ b()๋ฅผ ๋ฌถ๋ ๊ฒฝ์ฐ๊ฐ ์๋๋ฐ
์ด ๊ฒฝ์ฐ๊ฐ, ์ฐ๋ฆฌ๊ฐ ๋ฒํ๊ธฐ ์ฌ์ด ์ค์๋ค.
package main
import (
"fmt"
)
func main() {
defer func() {
a()
b()
}()
panic("panic!")
}
func a() {
r := recover()
fmt.Println("recoverd: ", r)
fmt.Println("a called")
}
func b() {
fmt.Println("b called")
}
recoverd: <nil>
a called
b called
panic: panic!
goroutine 1 [running]:
main.main()
/tmp/sandbox866461673/main.go:13 +0x60
Program exited: status 2.
์๊ฐ๋๋ก๋ผ๋ฉด ๋น์ฐํ aํจ์์์ recover๋ฅผ ํ๊ณ ์์ด panic์ ๋ง์ ์ ์์ ๊ฒ๋ง ๊ฐ์ง๋ง ์๋๋ค.
์ต๋ช ํจ์ ํธ์ถ -> a ํธ์ถ(recover) ๊ณผ ๊ฐ์ด ํจ์๋ฅผ 2๋ฒ ํ๊ธฐ ๋๋ฌธ์ depth๊ฐ ๋ฌ๋ผ์ ธ panic์ ๋ง์ง ๋ชปํ๋ค.
๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ๋ panic์ ์ฒ๋ฆฌํ์ง ๋ชปํ๋ค.
package main
func main() {
defer recover()
panic("panic!")
}
panic: panic!
goroutine 1 [running]:
main.main()
/tmp/sandbox609508284/main.go:5 +0x60
Program exited: status 2.
Go ์คํผ์ ์์๋ ๋ค์๊ณผ ๊ฐ์ด ๋งํ๊ณ ์๋ค.
The return value of recover is nil if any of the following conditions holds:
- panic's argument was nil;
- the goroutine is not panicking;
- recover was not called directly by a deferred function.
recover was not called directly by a deferred function.
์ฆ, recover๋ ์ง์ฐ๋ ํจ์์ ์ํด ์ง์ ์ ์ผ๋ก ํธ์ถ๋๋ฉด ์๋๋ค๋ ๋ป์ด๋ค.
์ฌ๊ธฐ์ recover๋ panic์ ์ค๋จ ์ํฌ ํจ์์ depth๊ฐ n์ด๋ผ๋ฉด recover๋ n+1์์ ํธ์ถํด์ผ panic์ ๋ง์ ์ ์๋ค๋ ๊ฒ์ ์ ์ถ ํ ์ ์๋๋ฐ ์ข ๋ ๊น๊ฒ ํ๋ค์ด๊ฐ ๋ณด์.
Panic์ด ์ฌ๋ฌ ๋ฒ ํธ์ถ๋๋ค๋ฉด?
๋ง์ฝ์ panic 1์ด mainํจ์ ๋ด์์ ๋ฐ์ํ์๊ณ defer๋ฌธ์์ panic 2๊ฐ ๋ ๋ฐ์ ํ๋ค๋ฉด recover๋ฅผ ํ๋ฉด panic 1์ด ์กํ ๊น? panic 2๊ฐ ์กํ๊น?
package main
import "fmt"
func main() {
defer fmt.Println("program will not crash")
defer func() {
fmt.Println( recover() ) // 3
}()
defer fmt.Println("now, panic 3 suppresses panic 2")
defer panic(3)
defer fmt.Println("now, panic 2 suppresses panic 1")
defer panic(2)
panic(1)
}
now, panic 2 suppresses panic 1
now, panic 3 suppresses panic 2
3
program will not crash
defer๋ฌธ์ ์ญ๋ฐฉํฅ์ผ๋ก ๋์ํ๊ธฐ ๋๋ฌธ์ ๊ฐ์ฅ ๋์ค์ ์ง์ฐ๋์ด ํธ์ถ๋ panic(3)์ด recover์ ์กํ๊ฒ ๋๋ค.
๊ทธ๋ ๋ค๋ฉด, ๋ง์ฝ panic์ด ๋ฐ์ํ๋ depth๊ฐ ์๋ก ๋ค๋ฅด๋ค๋ฉด..?
package main
import "fmt"
func main() { // call depth 0
defer fmt.Println("to crash, for panic 3 is still active")
defer func() { // call depth 1
defer func() { // call depth 2
fmt.Println( recover() ) // 6
}()
// The depth of panic 3 is 0,
// and the depth of panic 6 is 1.
defer fmt.Println("now, two active panics: 3 and 6")
defer panic(6) // will suppress panic 5
defer panic(5) // will suppress panic 4
// The following panic will not suppress
// panic 3, for they have different depths.
// The depth of panic 3 is 0.
// The depth of panic 4 is 1.
panic(4)
}()
defer fmt.Println("now, only panic 3 is active")
defer panic(3) // will suppress panic 2
defer panic(2) // will suppress panic 1
panic(1)
}
now, only panic 3 is active
now, there are two active panics: 3 and 6
6
program will crash, for panic 3 is still active
panic: 1
panic: 2
panic: 3
goroutine 1 [running]
...
์์ ๊ฒฐ๊ณผ๋ฅผ ๋ถ์ํ๋ฉด panic(1) -> panic(2) -> panic(3) -> panic(4) -> panic(5) -> panic(6) ์์ผ๋ก ํจ๋์ด ๋ฐ์ํ์๊ณ
1, 2, 3์ depth 0 ๊ทธ๋ฆฌ๊ณ 4, 5, 6์ depth 1์์ ๋ฐ์ํ์๋ค.
depth 1์์ ๊ฐ์ฅ ๋์ค์ ๋ฐ์ํ panic(6)์ด 4์ 5๋ฅผ ๋ฎ์ด ์์ ๊ณ depth 2์ recover์ ์ํด ๋ณต๊ตฌ๋์๋ค.
depth 2์ recover๋ depth 1์ panic(6)์ ๋ณต๊ตฌํ ๊ฒ์ด์ง depth 0์ panic์๋ ์ํฅ์ ๋ฏธ์น์ง ์๊ธฐ ๋๋ฌธ์ panic(3)๋ฅผ ์ฒ๋ฆฌํ์ง ๋ชปํ๊ณ ํ๋ก๊ทธ๋จ์ ์ข ๋ฃ๋๋ค.
๊ฒฐ๋ก
recover ํธ์ถ์ด ์ ์ฉ๋๋ ๊ท์น์ ๊ฐ๋จํ๊ฒ ๋ค์๊ณผ ๊ฐ๋ค.
ํจ์ f์ depth๊ฐ n์ด๊ณ , f์์ panic์ด ๋ฐ์ํ์ฌ ๋ณต๊ตฌํ๊ณ ์ถ๋ค๋ฉด recover๋ ์ง์ฐ ํธ์ถ๋์ด์ผ ํ๊ณ depth๋ n+1์ด ๋์ด์ผ ํ๋ค.
์ธ์ฉ: https://go101.org/article/panic-and-recover-more.html
The Right Places to Call the recover Function - Go 101 (Golang Knowledgebase)
Panic and recover mechanism has been introduced before, and several panic/recover use cases are shown in the last article. We know that a recover call can only take effect if it is invoked in a deferred function call. However, not all recover calls in defe
go101.org
'Language > Go' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Go] ์คํ์ค์ธ ํ๋ก์ธ์ค์ ๋ํด memory dump ํ์ผ์ ๋จ๊ธฐ๊ณ GoLand๋ก ๋ถ์ํ๊ธฐ (0) | 2019.11.05 |
---|---|
Go์์ ์์ฃผ ์ฌ์ฉํ๋ reflect ๊ตฌ๋ฌธ (Golang reflect) (2) | 2019.06.21 |
๋๊ธ
์ด ๊ธ ๊ณต์ ํ๊ธฐ
-
๊ตฌ๋
ํ๊ธฐ
๊ตฌ๋ ํ๊ธฐ
-
์นด์นด์คํก
์นด์นด์คํก
-
๋ผ์ธ
๋ผ์ธ
-
ํธ์ํฐ
ํธ์ํฐ
-
Facebook
Facebook
-
์นด์นด์ค์คํ ๋ฆฌ
์นด์นด์ค์คํ ๋ฆฌ
-
๋ฐด๋
๋ฐด๋
-
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
-
Pocket
Pocket
-
Evernote
Evernote
๋ค๋ฅธ ๊ธ
-
[Go] ์คํ์ค์ธ ํ๋ก์ธ์ค์ ๋ํด memory dump ํ์ผ์ ๋จ๊ธฐ๊ณ GoLand๋ก ๋ถ์ํ๊ธฐ
[Go] ์คํ์ค์ธ ํ๋ก์ธ์ค์ ๋ํด memory dump ํ์ผ์ ๋จ๊ธฐ๊ณ GoLand๋ก ๋ถ์ํ๊ธฐ
2019.11.05 -
Go์์ ์์ฃผ ์ฌ์ฉํ๋ reflect ๊ตฌ๋ฌธ (Golang reflect)
Go์์ ์์ฃผ ์ฌ์ฉํ๋ reflect ๊ตฌ๋ฌธ (Golang reflect)
2019.06.21