Dav*_*vid 5 concurrency channel go goroutine
func First(query string, replicas ...Search) Result {
c := make(chan Result)
searchReplica := func(i int) {
c <- replicas[i](query)
}
for i := range replicas {
go searchReplica(i)
}
return <-c
}
Run Code Online (Sandbox Code Playgroud)
这个函数来自Rob Pike在2012年的并发模式上的幻灯片.我认为这个函数存在资源泄漏.当第一个发送和接收对发生在通道c上后,函数返回,其他的例程尝试在通道c上发送.所以这里有资源泄漏.谁知道golang好可以证实这一点?如何使用什么样的golang工具检测这种泄漏?
icz*_*cza 11
是的,你是对的(作为参考,这里是幻灯片的链接).在上面的代码中,只有一个启动的goroutine将终止,其余的将在尝试发送通道时挂起c.
详图:
c 是一个无缓冲的频道return声明中只有一个接收操作replicasc请注意,取决于replicas(的元素len(replicas))的数量:
0:First()将永远阻止(没有人发送任何东西c)1:将按预期工作> 1:那么它会泄漏资源以下修改版本不会通过使用非阻塞发送(在selectwith default分支的帮助下)泄漏goroutine :
searchReplica := func(i int) {
select {
case c <- replicas[i](query):
default:
}
}
Run Code Online (Sandbox Code Playgroud)
第一个够程愿与结果将发送信道c将由够程运行的接收First(),在return声明.所有其他goroutines,当他们有结果将尝试发送通道,并"看到"它没有准备好(发送将阻止,因为没有人准备从它接收),default分支将被选择,因此goroutine将结束一般.
另一种解决方法是使用缓冲通道:
c := make(chan Result, len(replicas))
Run Code Online (Sandbox Code Playgroud)
这样发送操作就不会阻塞.当然,只有一个(第一个发送的)值将从频道收到并返回.
请注意,以上述任何修复的解决方案仍然会阻止如果len(replicas)是0.为避免这种情况,First()应明确检查,例如:
func First(query string, replicas ...Search) Result {
if len(replicas) == 0 {
return Result{}
}
// ...rest of the code...
}
Run Code Online (Sandbox Code Playgroud)
一些用于检测泄漏的工具/资源: