2016-10-19 32 views
0

最近我開發了一個golang TCP網絡編程框架名稱Tao,在文件util.go中有一個併發映射叫做ConnectionMap我用它來管理傳入的TCP連接,它是一個int64連接映射,通過多重讀寫-routines。這張併發地圖有什麼問題?

然後我開發了一個基於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 
} 

回答

1

IterKeysIterValues可以阻止所有的作家如果不正確使用。您正在使用非緩衝通道並鎖定整個地圖直到讀取所有值。請記住,只有在釋放所有讀鎖後,寫鎖才能被獲取。任何不會消耗頻道的來電者都會在讀取鎖定時泄漏一個goroutine。

有很多種解決方案,我能想到的:

  1. 確保,任何主叫方將盡可能快的排出通道。
  2. 根本不要使用goroutines。在讀取鎖定期間,同步迭代地圖。
  3. 您可以通過使用兩個通道使鎖定更細化。其中一個將表示您想讀取一個值,其次將鎖定地圖,讀取值,解鎖地圖併發送值。這樣呼叫者可以在不鎖定整個地圖的情況下儘可能多地佔用他所需的時間。

我支持第二種解決方案。正確實施,更容易理解和使用更容易。第一個太脆弱了,而第三個太複雜了,可能沒有必要。它也會慢很多。

+0

非常感謝!它適用於我:)最後,我選擇了選項2清理IterKeys()和IterValues()函數,同步迭代地圖,經過一天一夜之後,似乎再也沒有發生過這樣的問題,但我仍在疑惑爲什麼go-routine泄漏,我檢查了所有的代碼,當我使用IterKeys()和IterValues()時,我耗盡了它們。也許多線程編程充滿了神祕感,就像女人一樣:) – leesper