GOLANG实现超时对象检测的最好理解的方式
| 
                         原文:https://gocn.io/article/328 依赖于心跳的系统,都需要超时检测。比如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的数目非常多,那么扫描时每次都需要锁定 一般来说,超时的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超时时,才真正锁住 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!  | 
                  
