自己言及器官

プログラマーワナビー

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".

このブログの記事は必要である範囲で他の著作物を引用していることがあります。また指摘・修正を受け付けます