2 回答
TA贡献1853条经验 获得超6个赞
从 golang 参考:
“延迟”语句调用一个函数,该函数的执行被推迟到周围函数返回的那一刻
当您调用 os.Exit(0) 时,您绕过了正常的返回过程,并且不会执行您的延迟函数。
此外,即使 deferred 在主 goroutine 中工作,其他 goroutine 中的 defer 也不会工作,因为它们会在返回之前死亡。
更好的代码架构可以让你得到类似的东西。您需要将长时间运行的流程视为工人。导出工作进程中的每个长时间运行的进程,并在调用工作进程后立即推迟任何清理工作。在主 goroutine 中使用 select 来捕获信号并同步工作
package main
import (
"fmt"
"io/ioutil"
"os"
"os/signal"
"syscall"
"time"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
ioutil.WriteFile("./foo.txt", []byte("foo"), 0644)
defer os.RemoveAll("./foo.txt")
// Worker 1
done := make(chan bool, 1)
go func(done chan bool) {
fmt.Println("worker 1 with bar ...")
ioutil.WriteFile("./bar.txt", []byte("bar"), 0644)
// various long running things
time.Sleep(3 * time.Second)
done <- true
}(done)
defer os.RemoveAll("./bar.txt")
// End worker1
s := make(chan os.Signal, 1)
signal.Notify(s, os.Interrupt)
signal.Notify(s, syscall.SIGTERM)
// Worker 2
done2 := make(chan bool, 1)
go func(done chan bool) {
fmt.Println("worker 2 ...")
time.Sleep(6 * time.Second)
done <- true
}(done2)
// End worker 2
select {
case <-s:
fmt.Println("Quiting with signal - exit")
case <-done:
<-done2
case <-done2:
<-done
}
return
}
这个选择是处理两个工人的一种快速而肮脏的方式,更好的方法是使用 sync.WaitGroup
TA贡献1856条经验 获得超11个赞
我建议不要依赖 defer,而是定义一个可以在 defer 或信号块中使用的可重用函数。像这样的东西:
package main
import (
"fmt"
"io/ioutil"
"os"
"os/signal"
"syscall"
)
func main() {
ioutil.WriteFile("./foo.txt", []byte("foo"), 0644)
cleanup := func(){
os.RemoveAll("./foo.txt")
os.RemoveAll("./bar.txt")
}
defer cleanup() //for normal return
go func() {
ioutil.WriteFile("./bar.txt", []byte("bar"), 0644)
for {
// various long running things
}
}()
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
signal.Notify(c, syscall.SIGTERM)
go func() {
<-c
fmt.Println("Received OS interrupt - exiting.")
cleanup()
os.Exit(0)
}()
for {
// various long running things
}
}
- 2 回答
- 0 关注
- 124 浏览
添加回答
举报