【发布时间】:2016-08-25 01:26:43
【问题描述】:
关于如何确保生成的 goroutine 在长时间运行的进程的上下文中正确“关闭”,我有一个基本的理解问题。我观看了有关该主题的演讲并阅读了有关最佳实践的信息。为了理解我的问题,请参考视频“高级 Go 并发模式”here
对于以下情况,如果您在您的机器上运行代码,请导出环境变量GOTRACEBACK=all,这样您就可以看到恐慌后的常规状态。
我把原始示例的代码放在这里:naive(它不会在go Playground上执行,我猜是因为使用了时间语句。请复制代码并在本地执行)
执行后naive实现的panic结果是
panic: show me the stacks
goroutine 1 [running]:
panic(0x48a680, 0xc4201d8480)
/usr/lib/go/src/runtime/panic.go:500 +0x1a1
main.main()
/home/flx/workspace/go/go-rps/playground/ball-naive.go:18 +0x16b
goroutine 5 [chan receive]:
main.player(0x4a4ec4, 0x2, 0xc42006a060)
/home/flx/workspace/go/go-rps/playground/ball-naive.go:23 +0x61
created by main.main
/home/flx/workspace/go/go-rps/playground/ball-naive.go:13 +0x76
goroutine 6 [chan receive]:
main.player(0x4a4ec6, 0x2, 0xc42006a060)
/home/flx/workspace/go/go-rps/playground/ball-naive.go:23 +0x61
created by main.main
/home/flx/workspace/go/go-rps/playground/ball-naive.go:14 +0xad
exit status 2
这说明了在系统上留下悬空的 goroutine 的潜在问题,这对于长时间运行的进程尤其不利。
因此,就我个人的理解而言,我尝试了两个稍微复杂的变体:
generator pattern with quit channel
(同样,不能在操场上执行,导致“处理时间过长”)
第一个解决方案由于各种原因不合适,甚至导致执行步骤的不确定性,具体取决于 goroutine 执行速度。
现在我想——问题终于来了! -- 使用退出通道的第二个解决方案适合在退出之前从系统中消除所有执行跟踪。无论如何,“有时”程序退出得太快,并且恐慌报告了一个额外的 goroutine 可运行仍然驻留在系统上。恐慌输出:
panic: show me the stacks
goroutine 1 [running]:
panic(0x48d8e0, 0xc4201e27c0)
/usr/lib/go/src/runtime/panic.go:500 +0x1a1
main.main()
/home/flx/workspace/go/go-rps/playground/ball-perfect.go:20 +0x1a9
goroutine 20 [runnable]:
main.player.func1(0xc420070060, 0x4a8986, 0x2, 0xc420070120)
/home/flx/workspace/go/go-rps/playground/ball-perfect.go:27 +0x211
created by main.player
/home/flx/workspace/go/go-rps/playground/ball-perfect.go:36 +0x7f
exit status 2
我的问题是:这不应该发生,对吧?在进入恐慌之前,我确实使用退出通道来清理状态。
我在这里做了最后一次实施安全清理行为的尝试: artificial wait time for runnables to close
无论如何,该解决方案感觉不对,也可能不适用于大量可运行文件?
为了确保正确清理,推荐和最惯用的模式是什么?
感谢您的宝贵时间
【问题讨论】:
-
我无法理解该示例如何演示“程序完成执行后系统上的悬空 goroutines”。 Goroutines 是一个 Go 运行时概念 - 当程序完成执行时会被拆除。您看到的是输出,而拆解仍在进行中。如果在此之前清理它们..运行时无法报告发生了什么。还是我完全不理解你所说的?
-
朴素示例中的例程无法退出,因为它们阻塞在共享通道上,等待球。视频中的重要部分是从约 4.40 分钟到约 5.10 分钟。程序本身会退出,但会留下悬空的例程。
-
对,我很抱歉 - 我没有意识到您是在长时间运行的进程的上下文中说话,而不是在运行进程的实际终止。
-
谢谢,我会编辑问题以便清楚!
标签: go concurrency stack-trace channel goroutine