如何退出接受延迟呼叫的go计划?
我需要使用如何退出接受延迟呼叫的go计划?,go,exit,deferred,Go,Exit,Deferred,我需要使用defer来释放使用Clibrary手动创建的分配,但我还需要os。在某个时刻以非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 fm
defer
来释放使用C
library手动创建的分配,但我还需要os。在某个时刻以非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)
}
游乐场:从
那么,如何退出接受已声明的
defer
调用的go程序呢?除了操作系统退出,还有其他选择吗?只需将程序向下移动一个级别并返回退出代码:
package main
import "fmt"
import "os"
func doTheStuff() int {
defer fmt.Println("!")
return 3
}
func main() {
os.Exit(doTheStuff())
}
经过一些研究,我发现了一个替代方案:
- 不会像中那样强加特定的体系结构
- 不需要像中那样的任何全局值
恐慌
和恢复
。事实证明,本质上,panic
会接受延迟
调用,但也会始终以非0
状态代码退出并转储堆栈跟踪。诀窍在于,我们可以用以下方法覆盖恐慌行为的最后一个方面:
package main
import "fmt"
import "os"
type Exit struct{ Code int }
// exit code handler
func handleExit() {
if e := recover(); e != nil {
if exit, ok := e.(Exit); ok == true {
os.Exit(exit.Code)
}
panic(e) // not an Exit, bubble up
}
}
现在,要在任何时候退出程序并仍然保留任何声明的defer
指令,我们只需要发出exit
类型:
func main() {
defer handleExit() // plug the exit handler
defer fmt.Println("cleaning...")
panic(Exit{3}) // 3 is the exit code
}
除了在func main
中插入一行代码外,它不需要任何重构:
func main() {
defer handleExit()
// ready to go
}
这在更大的代码基础上可以很好地扩展,所以我将把它留给仔细检查。希望能有帮助
操场:是实现这一目标的简单方法
Goexit终止了称之为goroutine的goroutine。没有其他goroutine受到影响Goexit在终止goroutine之前运行所有延迟调用。因为Goexit不是死机,但是,这些延迟函数中的任何recover调用都将返回nil
然而:
从主goroutine调用Goexit将终止该goroutine,而不返回func main。由于func main尚未返回,程序将继续执行其他goroutine。如果所有其他goroutine退出,程序将崩溃
因此,如果您从主goroutine调用它,则需要在main
的顶部添加
defer os.Exit(0)
下面,您可能想添加一些其他的
延迟
语句,通知其他goroutine停止并清理。对于后代来说,这是一个更优雅的解决方案:
func main() {
retcode := 0
defer func() { os.Exit(retcode) }()
defer defer1()
defer defer2()
[...]
if err != nil {
retcode = 1
return
}
}
@ctcherry延迟
操作系统没有成功。退出
:反转延迟顺序哦,我明白了,这是个问题。在我的情况下,我只能延迟os。在运行其他也延迟某些内容的操作后退出。。。让我再想想。main
中的defer
与os结合使用。退出
肯定是个棘手的问题。像下面的@Rob Napier那样围绕它进行架构是一种更好的方法。因此,我不应该在func main
内部使用defer
或任何退出的函数?更重要的是,我不建议在代码中的随机位置使用os.Exit()
。除了错误代码的问题外,这使得测试非常困难。peterSO的解决方案@ctcherry links是可以的,但是它不能很好地扩展到更大的程序中。您必须将代码
设置为全局。我相信你应该保持main()相当简单,让它只处理操作系统级别的事情(比如最终状态代码)。无论如何,+1,因为总是先尝试亲吻是个好建议。我不知道runtime.Goexit()
的存在。这是最近发布的吗?@marcio我在Go存储库中做了一些挖掘。我找不到它的确切介绍时间,但我确实在你发布这个问题之前找到了。@marcio我做了更多的挖掘并找到了。Goexit列在那里。我将把它标记为可接受的答案。其他答案肯定仍然有效,但这似乎是最简单的方法——就目前而言:迄今为止最好的答案!一个问题,如何处理正常退出呢?如何确保在正常退出的情况下调用handleExit
?Ref:un comment the//panic
并查看其区别。我认为正常退出0事件的句柄不存在,但您可以总是先进行panic(退出{0}),然后再进行处理,或者在main()上执行任何其他操作之前延迟handleNormalExit()?这确实占用了其他答案中最好的部分。