[英]Deadlock with buffered channel
我有一些代碼是作業調度程序,正在整理來自許多TCP套接字的大量數據。 這段代碼是使用大量瞬態對象的方法的結果-避免了爭用,並且在很大程度上降低了CPU使用率並且現在鎖定也不是問題。
我的應用程序有時會鎖定,並且“通道長度”日志是唯一重復發生的事情,因為仍然有數據從我的套接字輸入。 但是,計數仍為5000,並且不進行任何下游處理。
我認為問題可能是競賽情況,並且可能掛斷的線路是jobDispatcher
select
中的channel <- msg
jobDispatcher
。 問題是我不知道如何驗證這一點。
我懷疑由於select可以隨機獲取項目,因此goroutine正在返回,shutdownChan沒有機會進行處理。 然后數據命中inboundFromTCP並阻塞!
可能有人在這里發現了明顯錯誤的地方。 並希望提供解決方案!?
var MessageQueue = make(chan *trackingPacket_v1, 5000)
func init() {
go jobDispatcher(MessageQueue)
}
func addMessage(trackingPacket *trackingPacket_v1) {
// Send the packet to the buffered queue!
log.Println("Channel length:", len(MessageQueue))
MessageQueue <- trackingPacket
}
func jobDispatcher(inboundFromTCP chan *trackingPacket_v1) {
var channelMap = make(map[string]chan *trackingPacket_v1)
// Channel that listens for the strings that want to exit
shutdownChan := make(chan string)
for {
select {
case msg := <-inboundFromTCP:
log.Println("Got packet", msg.Avr)
channel, ok := channelMap[msg.Avr]
if !ok {
packetChan := make(chan *trackingPacket_v1)
channelMap[msg.Avr] = packetChan
go processPackets(packetChan, shutdownChan, msg.Avr)
packetChan <- msg
continue
}
channel <- msg
case shutdownString := <-shutdownChan:
log.Println("Shutting down:", shutdownString)
channel, ok := channelMap[shutdownString]
if ok {
delete(channelMap, shutdownString)
close(channel)
}
}
}
}
func processPackets(ch chan *trackingPacket_v1, shutdown chan string, id string) {
var messages = []*trackingPacket_v1{}
tickChan := time.NewTicker(time.Second * 1)
defer tickChan.Stop()
hasCheckedData := false
for {
select {
case msg := <-ch:
log.Println("Got a messages for", id)
messages = append(messages, msg)
hasCheckedData = false
case <-tickChan.C:
messages = cullChanMessages(messages)
if len(messages) == 0 {
messages = nil
shutdown <- id
return
}
// No point running checking when packets have not changed!!
if hasCheckedData == false {
processMLATCandidatesFromChan(messages)
hasCheckedData = true
}
case <-time.After(time.Duration(time.Second * 60)):
log.Println("This channel has been around for 60 seconds which is too much, kill it")
messages = nil
shutdown <- id
return
}
}
}
更新01/20/16
我嘗試將channelMap
用作帶有一些互斥鎖的全局對象,但最終仍然死鎖。
稍微調整了代碼,仍然鎖定,但我不知道這是怎么做的! https://play.golang.org/p/PGpISU4XBJ
更新01/21/17在提出一些建議之后,我將其放入一個獨立的工作示例中,以便人們看到。 https://play.golang.org/p/88zT7hBLeD
這是一個長期運行的過程,因此在游樂場將其殺死時,需要在計算機上本地運行。 希望這可以幫助您找到根底!
我猜測您的問題在另一個goroutine正在執行shutdown <- id
的同時,正在執行此channel <- msg
-msg。
由於channel
和shutdown
通道均未緩沖,因此它們阻塞了等待接收器的時間。 他們可以陷入僵局,等待另一邊變得可用。
有幾種解決方法。 您可以使用緩沖區1聲明這兩個通道。
或者,您可以執行Google的上下文包的操作,並通過關閉關閉通道來發送關閉信號,而不是通過發送關閉消息來發出信號。 查看https://golang.org/pkg/context/,尤其是WithCancel
, WithDeadline
和Done
函數。
您可能可以使用上下文來刪除自己的關閉通道和超時代碼。
JimB提出了在可能仍在通道上接收goroutine的同時將其關閉的觀點。 您應該執行的操作是發送關閉消息(或關閉或取消上下文),並繼續處理消息,直到關閉您的ch
通道(以case msg, ok := <-ch:
,這將在發送方收到關機信息。
這樣,您將獲得所有傳入的消息,直到實際發生關閉為止,並且應該避免再次出現死鎖。
我是Go的新手,但是在這里的代碼中
case msg := <-inboundFromTCP:
log.Println("Got packet", msg.Avr)
channel, ok := channelMap[msg.Avr]
if !ok {
packetChan := make(chan *trackingPacket_v1)
channelMap[msg.Avr] = packetChan
go processPackets(packetChan, shutdownChan, msg.Avr)
packetChan <- msg
continue
}
channel <- msg
您不是在這里放一些東西(無緩沖嗎?)
channel, ok := channelMap[msg.Avr]
因此,在添加味精之前,您是否需要清空該頻道?
channel <- msg
就像我說的那樣,我是Go的新手,所以我希望自己不要傻。 :)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.