這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
Go語言最方便的地方在於可以自由自在的起routine,並且不用自己維護隊列。
一個很簡單的處理模型,針對於長串連活動平凡的連結獨立routine進行處理,方便同一串連上下文關聯,read routine A講接收到的訊息解包產生訊息丟到對應socket的routine B channel中進行處理,routine B在根據不同的任務丟到對應的routine B1或者 routine B2中進行處理,
我們需要一個channel回寫routine B1 routine B2的退出訊號給你 B 以便B進行響應處理。
那麼這麼想的話 B 和B1 B2 需要兩個channel進行訊息通訊
虛擬碼如下,未做友好處理。
var B1 B1Consumervar B2 B2Consumer//statch 回寫子routine的狀態statch := make(chan StatMsg,1)B1Ch := make(chan Msg,100)B2Ch := make(chan Msg,100)go B1(B1ch,statch)go B2(B2ch,statch)for{ select{ case cmsg, ok := <-BCh: if cmsg.type == B1{ B1ch<-cmsg }else{ B2ch<-cmsg } case StatMsg := <-statch: deal_state(msg) }}
乍一看沒什麼問題,後面再測試過程中 偶爾發現調用介面沒有響應逾時。
仔細排查後發現,B1 routine 在退出時回寫了一個Done的StatMsg,然後就退出了。
此事Bch還在寫資料如果此時B1ch寫滿了,那麼寫channel就會卡死,而B1退出的訊號已經發送了 不在處理新資料了,那麼B routine就會一直卡死在
B1ch<-cmsg
此時已經B routine 已經無法進行下一次select的操作,進而等Bch channel寫滿 卡死讀取routine,等多個讀取routine卡死,用戶端表現就是無響應了 逾時了。
找到問題解決辦法就簡單了。
增加寫入channel逾時 並且增加statch 的大小
statch := make(chan StatMsg,MAXCHANNELSIZE) select { case B1ch <- cmsg: case <-time.After(time.Duration(CLOSETIMEOUT) * time.Second):}
加大channel大小 避免多次觸發逾時,如果一旦出現逾時,將逾時的任務釋放掉。