diff --git a/client.go b/client.go index 6a3457e..b907b53 100644 --- a/client.go +++ b/client.go @@ -664,16 +664,7 @@ func clientGetURLDeadlineFreeConn(dst []byte, url string, deadline time.Time, c } }() - var tc *time.Timer - tcv := timerPool.Get() - if tcv == nil { - tc = time.NewTimer(timeout) - tcv = tc - } else { - tc = tcv.(*time.Timer) - initTimer(tc, timeout) - } - + tc := acquireTimer(timeout) select { case resp := <-ch: ReleaseRequest(req) @@ -685,9 +676,7 @@ func clientGetURLDeadlineFreeConn(dst []byte, url string, deadline time.Time, c body = dst err = ErrTimeout } - - stopTimer(tc) - timerPool.Put(tcv) + releaseTimer(tc) return statusCode, body, err } @@ -916,16 +905,7 @@ func clientDoDeadlineFreeConn(req *Request, resp *Response, deadline time.Time, ch <- c.Do(reqCopy, respCopy) }() - var tc *time.Timer - tcv := timerPool.Get() - if tcv == nil { - tc = time.NewTimer(timeout) - tcv = tc - } else { - tc = tcv.(*time.Timer) - initTimer(tc, timeout) - } - + tc := acquireTimer(timeout) var err error select { case err = <-ch: @@ -939,17 +919,12 @@ func clientDoDeadlineFreeConn(req *Request, resp *Response, deadline time.Time, case <-tc.C: err = ErrTimeout } - - stopTimer(tc) - timerPool.Put(tcv) + releaseTimer(tc) return err } -var ( - errorChPool sync.Pool - timerPool sync.Pool -) +var errorChPool sync.Pool // Do performs the given http request and sets the corresponding response. // diff --git a/tcpdialer.go b/tcpdialer.go index b074d00..ffb37a8 100644 --- a/tcpdialer.go +++ b/tcpdialer.go @@ -205,8 +205,18 @@ func tryDial(network string, addr *net.TCPAddr, deadline time.Time, concurrencyC select { case concurrencyCh <- struct{}{}: - case <-time.After(timeout): - return nil, ErrDialTimeout + default: + tc := acquireTimer(timeout) + isTimeout := false + select { + case concurrencyCh <- struct{}{}: + case <-tc.C: + isTimeout = true + } + releaseTimer(tc) + if isTimeout { + return nil, ErrDialTimeout + } } timeout = -time.Since(deadline) @@ -215,7 +225,11 @@ func tryDial(network string, addr *net.TCPAddr, deadline time.Time, concurrencyC return nil, ErrDialTimeout } - ch := make(chan dialResult, 1) + chv := dialResultChanPool.Get() + if chv == nil { + chv = make(chan dialResult, 1) + } + ch := chv.(chan dialResult) go func() { var dr dialResult dr.conn, dr.err = net.DialTCP(network, nil, addr) @@ -223,14 +237,27 @@ func tryDial(network string, addr *net.TCPAddr, deadline time.Time, concurrencyC <-concurrencyCh }() + var ( + conn net.Conn + err error + ) + + tc := acquireTimer(timeout) select { case dr := <-ch: - return dr.conn, dr.err - case <-time.After(timeout): - return nil, ErrDialTimeout + conn = dr.conn + err = dr.err + dialResultChanPool.Put(ch) + case <-tc.C: + err = ErrDialTimeout } + releaseTimer(tc) + + return conn, err } +var dialResultChanPool sync.Pool + type dialResult struct { conn net.Conn err error diff --git a/timer.go b/timer.go index 4693ecf..bb12acb 100644 --- a/timer.go +++ b/timer.go @@ -1,6 +1,7 @@ package fasthttp import ( + "sync" "time" ) @@ -24,3 +25,20 @@ func stopTimer(t *time.Timer) { } } } + +func acquireTimer(timeout time.Duration) *time.Timer { + v := timerPool.Get() + if v == nil { + return time.NewTimer(timeout) + } + t := v.(*time.Timer) + initTimer(t, timeout) + return t +} + +func releaseTimer(t *time.Timer) { + stopTimer(t) + timerPool.Put(t) +} + +var timerPool sync.Pool