2017-03-13 43 views
0

Redigo是Redis数据库的golang客户端。它使用struct Pool来维护一个连接池。这个结构为应用程序放置和并行连接保存互斥锁。redigo连接池 - 为何在删除过期连接时释放锁

type Pool struct { 
    // ... 
    IdleTimeout time.Duration 
    mu  sync.Mutex 
    // Stack of idleConn with most recently used at the front. 
    idle list.List 
} 

在其get方法中,连接池首先删除失效(空闲超时)连接。当发现一个陈旧的连接时,池弹出它,释放锁定,然后关闭连接,尝试再次获取锁定。

func (p *Pool) get() (Conn, error) { 
    p.mu.Lock() 

    // Prune stale connections. 

    if timeout := p.IdleTimeout; timeout > 0 { 
     for i, n := 0, p.idle.Len(); i < n; i++ { 
      e := p.idle.Back() 
      if e == nil { 
       break 
      } 
      ic := e.Value.(idleConn) 
       if ic.t.Add(timeout).After(nowFunc()) { 
        break 
       } 
      p.idle.Remove(e) 
      p.release() 
      // Why does pool unlock and try to acquire lock again? 
      p.mu.Unlock() 
      // Close this stale connection. 
      ic.c.Close() 
      p.mu.Lock() 
     } 
    } 

为什么游泳池解锁并尝试再次获取锁定,而不是在函数返回之前解锁?我想关闭连接可能会花费很多时间,这会减慢其他等待这个互斥量的goroutine。

这里是整个Pool get method

+0

我认为你的猜测是正确的。关闭连接可能需要很长时间。现在锁定所有使用池似乎是不明智的。 –

回答

0

关闭的连接可能会花费相当多的时间,这将其他的goroutine等待此互斥放缓。正如@CeriseLimón所说 - 现在锁定所有游泳池的使用似乎是不明智的。

解锁互斥锁后,其中一个等待的互联网获取互斥锁。尽管get方法仍然需要删除过时的连接,但方法put的方法可以将连接放到池中并尽快继续做其他工作。

+0

“关闭连接可能花费相当多的时间” - 这需要一些细节。在引擎盖下它实现为'err:= c.fd.Close()'。在什么情况下这可能会变慢? – zerkms

+0

@zerkms说实话,我不明白net/fd_unix.go中的底层'netFD.Close'。理论上,当tcp正常终止时,每一方(客户端和服务器)都会发送FIN并从另一端接收ACK。在此期间,网络延迟和数据包丢失可能存在。 – lorneli