GOLANG實現超時物件檢測的最好理解的方式
依賴於心跳的系統,都需要超時檢測。比如 P2P 系統中客戶端每隔 120 秒向資料伺服器傳送一次資料彙總,伺服器就需要維護一個超時時間。比如一個 UDP 伺服器,在和客戶端之間建立 Session 之後,如果沒有資料包,一般會有 Ping 包,說明這個 Session 是存活的,伺服器在發現 Session 超時後也需要清理。
首先,伺服器一般需要維護一個列表,以 Peer 為例:
type Peer struct {
id uint64
heartbeat time.Time
}
type Server struct {
peers map[uint64]*Peer
lock sync.Mutex
}
建立 Peer,同時在收到 Ping 訊息後,更新 Peer 的心跳時間:
func (v *Server) Create(id uint64) *Peer {
v.lock.Lock()
defer v.lock.UnLock()
p = &Peer { id:id, heartbeat: time.Now(), }
v.peers[id] = p
return p
}
func (v *Server) OnPing(id uint64) {
v.lock.Lock()
defer v.lock.UnLock()
if p,ok := v.peers[id]; ok {
p.heatbeat = time.Now()
}
}
當然,需要起一個 goroutine 定期掃描這個列表, 假設 300 秒超時:
go func(v *Server) {
for {
func(){
v.lock.Lock()
defer v.lock.UnLock()
now := time.Now()
for id,p := range v.peers {
if p.heartbeat.Add(300 * time.Second).Before(now) {
delete(v.peers, id)
}
}
}()
time.Sleep(30 * time.Second)
}
}(server)
如果 Peers 的數目非常多,那麼掃描時每次都需要鎖定v.peers
,會導致其他的業務都無法進行。特別是清理 Peer 這個過程如果比較複雜,譬如需要發起 io 請求,是一個費時的操作時,就會造成系統的等待。
一般來說,超時的 Peer 不會很多,因此可以用 chan 放一個超時的 peer,每個 peer 專門起一個 goroutine 來看什麼時候超時,這樣就可以在檢測超時時避免用鎖了:
timeout := make(chan *Peer)
func (v *Server) Create(id uint64) *Peer {
v.lock.Lock()
defer v.lock.UnLock()
p = &Peer { id:id, heartbeat: time.Now(), }
v.peers[id] = p
return p
go func(p *Peer) {
for {
tm := p.heartbeat
<- time.After(300 * time.Second)
if tm.Equal(p.heartbeat) {
timeout <- p
break
}
}
}(p)
}
go func(v *Server){
for gw := range timeout {
func(){
lgateways.Lock()
defer lgateways.Unlock()
delete(gateways, gw.port)
}()
// Do something cleanup about the gateway.
}
}(server)
這樣就只有在有 Peer 超時時,才真正鎖住Server.peers
。
檢測超時時,除了用heartbeat
心跳時間,還可以用keepAlive chan bool
保活訊息來實現:
type Peer struct {
keepAlive chan bool
}
func (v *Server) OnPing(id uint64) {
if p,ok := v.peers[id]; ok {
select {
case p.keepAlive <- true:
default:
}
}
}
這樣檢測超時也更簡單:
go func(p *Peer) {
for {
select {
case <- time.After(300 * time.Second):
timeout <- p
case <- p.keepAlive:
}
}
}(p)
這樣就是兩個 chan 聯合完成這個任務:
keepAlive => timeout
更多原創文章乾貨分享,請關注公眾號
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- 實時微信域名檢測API介面的實現方式API
- Golang利用select實現超時機制Golang
- 微信域名檢測的機制原理以及實現方式
- Python實時物件檢測入門指南Python物件
- GOLANG使用Context實現傳值、超時和取消GolangContext
- 微信域名防封檢測的技術原理及實現方式
- 這是一篇人臉檢測基本實現最好懂的實踐指南了!
- redis主從超時檢測Redis
- 網路程式設計中的超時檢測程式設計
- 層級時間輪的 Golang 實現Golang
- 微信域名批次檢測 微信域名攔截查詢的實現方式
- 深入理解Vue的watch實現原理及其實現方式Vue
- 介面呼叫超時的實現原理
- golang 執行時死鎖排查和檢測Golang
- 超實用:實現負載均衡技術的方式負載
- 深入理解Vue的computed實現原理及其實現方式Vue
- 深入理解 JDBC 的超時JDBC
- 一種新的頁面載入時間檢測方式
- Java物件表示方式2:XStream實現對物件的XML化Java物件XML
- Golang 物件導向深入理解Golang物件
- 物件~時間篇_日曆的實現物件
- Golang 心跳的實現Golang
- JavaScript人臉檢測的實現方法JavaScript
- 使用SlimYOLOv3框架實現實時目標檢測YOLO框架
- Javascript 中實現物件原型繼承的三種方式JavaScript物件原型繼承
- Go定時器的三種實現方式Go定時器
- pymysql 處理 連線超時最好的解決方案MySql
- 基於時間序列檢測演算法的智慧報警實現演算法
- 物體檢測實戰:使用 OpenCV 進行 YOLO 物件檢測OpenCVYOLO物件
- 密碼加密的最好方式密碼加密
- IOS橫線滾動檢視的實現---方式二iOS
- 微信域名檢測線上批次檢測如何實現?——利用域名檢測api介面實現批次檢測工具教程API
- 實時的空號檢測API,穩定可靠API
- 檢測LINUX程式的實時IO情況Linux
- 原生javascript實現的檢測字串長度JavaScript字串
- 深入理解JDBC的超時設定JDBC
- Common Lisp物件系統是現存最好的物件系統? - mendhekarLisp物件
- 幾種實現延時任務的方式(一)