一尘不染

如何退出执行延迟调用的 go 程序?

go

我需要defer使用C库来释放手动创建的分配,但我也需要os.Exit在某些时候使用非 0 状态。棘手的部分是os.Exit跳过任何延迟指令:

package main

import "fmt"
import "os"

func main() {

    // `defer`s will _not_ be run when using `os.Exit`, so
    // this `fmt.Println` will never be called.
    defer fmt.Println("!")
    // sometimes ones might use defer to do critical operations
    // like close a database, remove a lock or free memory

    // Exit with status code.
    os.Exit(3)
}

阅读 175

收藏
2021-12-11

共2个答案

一尘不染

只需将您的程序向下移动一个级别并返回您的退出代码:

package main

import "fmt"
import "os"

func doTheStuff() int {
    defer fmt.Println("!")

    return 3
}

func main() {
    os.Exit(doTheStuff())
}
2021-12-11
一尘不染

runtime.Goexit() 是实现这一目标的简单方法。

Goexit 终止调用它的 goroutine。没有其他 goroutine 受到影响。Goexit 在终止 goroutine 之前运行所有延迟调用。然而,因为 Goexit 并不恐慌,这些延迟函数中的任何恢复调用都将返回 nil。

然而:

从主协程调用 Goexit 会终止该协程,而不会返回 func main。由于 func main 没有返回,程序继续执行其他 goroutine。如果所有其他 goroutine 退出,程序就会崩溃。

所以如果你从主goroutine调用它,main你需要在顶部添加

defer os.Exit(0)

在此之下,您可能想要添加一些其他defer语句,以通知其他 goroutine 停止和清理。

2021-12-11