1 回答
TA贡献2080条经验 获得超4个赞
您的代码的问题是双重的。
首先,理论上存在goroutine泄漏,因为任何向容量为零的通道(无缓冲通道或已满缓冲通道)发送值的尝试都会阻塞发送 goroutine,直到在该通道上完成接收操作。
所以,是的,根据通道工作方式的定义,所有三个 goroutine 都将在numChan <- num
语句中被阻止。
其次,由于 Go 的一些修改,panic
默认情况下未处理的只转储恐慌 goroutine 的堆栈跟踪。如果你想转储所有活动的 goroutines 的堆栈,你必须调整运行时——来自包的文档runtime
:
该
GOTRACEBACK
变量控制当 Go 程序由于未恢复的恐慌或意外的运行时条件而失败时生成的输出量。默认情况下,失败会打印当前 goroutine 的堆栈跟踪,省略运行时系统内部的函数,然后以退出代码 2 退出。如果没有当前 goroutine 或失败是,则失败会打印所有 goroutine 的堆栈跟踪运行时内部。GOTRACEBACK=none
完全省略 goroutine 堆栈跟踪。GOTRACEBACK=single
(默认值)的行为如上所述。GOTRACEBACK=all
为所有用户创建的 goroutines 添加堆栈跟踪。GOTRACEBACK=system
类似于“all”,但为运行时函数添加堆栈帧并显示运行时内部创建的 goroutine。GOTRACEBACK=crash
类似于“系统”,但以特定于操作系统的方式崩溃而不是退出。例如,在 Unix 系统上,崩溃SIGABRT
引发核心转储。由于历史原因,GOTRACEBACK
设置 0、1 和 2 分别是 none、all 和 system 的同义词。The runtime/debug
package 的SetTraceback
功能允许在运行时增加输出量,但它不能减少到低于环境变量指定的量。
另请注意,您绝不能使用计时器进行(模拟)同步:在玩具示例中,这可能有效,但在现实生活中,没有什么能阻止您的三个 goroutine 在您的主 goroutine 在调用中花费的时间跨度内没有机会运行到time.Sleep
——所以结果可能是任何数量的派生 goroutines 已经运行:从 0 到 3。
在那里添加一个事实,即当main
退出运行时时,运行时只会杀死所有未完成的活动 goroutines,并且测试结果充其量可能是令人惊讶的。
因此,一个适当的解决方案是
仅在需要的地方打印堆栈,
确保通过匹配的接收同步发送:
package main
import (
"fmt"
"log"
"runtime"
)
func dumpStacks() {
buf := make([]byte, 32 * 1024)
n := runtime.Stack(buf, true)
log.Println(string(buf[:n]))
}
func main() {
numCount := 3
numChan := make(chan int, numCount)
for i := 0; i < numCount; i++ {
go func(num int) {
fmt.Printf("Adding num: %d to chan\n", num)
numChan <- num
fmt.Printf("Adding num: %d to chan Done\n", num)
}(i)
}
dumpStacks()
for i := 0; i < numCount; i++ {
<-numChan
}
}
游乐场。
- 1 回答
- 0 关注
- 116 浏览
添加回答
举报