最近我开发了一个golang TCP网络编程框架名称Tao,在文件util.go中有一个名为 ConnectionMap 的并发映射,我用它来管理传入的TCP连接,它是由多个go-routines读取和写入的int64-to-Connection映射。
然后我开发了一个基于Tao的远程控制系统,移动应用程序可以通过该系统控制设备。但是我发现 ConnectionMap 有问题:某些已经关闭的连接不会从此地图中删除并保持存在。
我不太确定这是一段时间之后应用程序很难连接到这个系统的原因,但我真的很困惑这是写出一个并发映射的正确方法吗?是不是错了? 谢谢。
type ConnectionMap struct{
sync.RWMutex
m map[int64]Connection
}
func NewConnectionMap() *ConnectionMap {
return &ConnectionMap{
m: make(map[int64]Connection),
}
}
func (cm *ConnectionMap)Clear() {
cm.Lock()
cm.m = make(map[int64]Connection)
cm.Unlock()
}
func (cm *ConnectionMap)Get(k int64) (Connection, bool) {
cm.RLock()
conn, ok := cm.m[k]
cm.RUnlock()
return conn, ok
}
func (cm *ConnectionMap)IterKeys() <-chan int64 {
kch := make(chan int64)
go func() {
cm.RLock()
for k, _ := range cm.m {
kch<- k
}
cm.RUnlock()
close(kch)
}()
return kch
}
func (cm *ConnectionMap)IterValues() <-chan Connection {
vch := make(chan Connection)
go func() {
cm.RLock()
for _, v := range cm.m {
vch<- v
}
cm.RUnlock()
close(vch)
}()
return vch
}
func (cm *ConnectionMap)Put(k int64, v Connection) {
cm.Lock()
cm.m[k] = v
cm.Unlock()
}
func (cm *ConnectionMap)Remove(k int64) {
cm.Lock()
delete(cm.m, k)
cm.Unlock()
}
func (cm *ConnectionMap)Size() int {
cm.RLock()
size := len(cm.m)
cm.RUnlock()
return size
}
func (cm *ConnectionMap)IsEmpty() bool {
return cm.Size() <= 0
}
答案 0 :(得分:1)
IterKeys
和IterValues
可以阻止所有作者。您正在使用非缓冲通道并锁定整个地图,直到读取所有值。请记住,只有在释放所有读锁后才能获取写锁。任何不会耗尽通道的调用者都会在读取锁定时泄漏goroutine。
我能想到多种解决方案:
我赞成第二种解决方案。它更容易实现,更容易理解和使用。第一个太脆弱了,而第三个太复杂了,可能没必要。它也会慢得多。