mirror of
https://github.com/valyala/fasthttp.git
synced 2026-06-14 15:56:44 +03:00
Eliminated memory allocations from client's DoTimeout and GetTimeout
This commit is contained in:
@@ -468,14 +468,19 @@ func clientGetURLTimeout(dst []byte, url string, timeout time.Duration, c client
|
||||
}
|
||||
}
|
||||
|
||||
type clientURLResponse struct {
|
||||
statusCode int
|
||||
body []byte
|
||||
err error
|
||||
}
|
||||
|
||||
func clientGetURLTimeoutFreeConn(dst []byte, url string, timeout time.Duration, c clientDoer) (statusCode int, body []byte, err error) {
|
||||
var ch chan error
|
||||
var ch chan clientURLResponse
|
||||
chv := errorChPool.Get()
|
||||
if chv == nil {
|
||||
ch = make(chan error, 1)
|
||||
} else {
|
||||
ch = chv.(chan error)
|
||||
chv = make(chan clientURLResponse, 1)
|
||||
}
|
||||
ch = chv.(chan clientURLResponse)
|
||||
|
||||
req := acquireRequest()
|
||||
|
||||
@@ -486,29 +491,32 @@ func clientGetURLTimeoutFreeConn(dst []byte, url string, timeout time.Duration,
|
||||
// Without this 'hack' the load on slow host could exceed MaxConns*
|
||||
// concurrent requests, since timed out requests on client side
|
||||
// usually continue execution on the host.
|
||||
var statusCodeCopy int
|
||||
var bodyCopy []byte
|
||||
go func() {
|
||||
var errCopy error
|
||||
statusCodeCopy, bodyCopy, errCopy = doRequest(req, dst, url, c)
|
||||
ch <- errCopy
|
||||
statusCodeCopy, bodyCopy, errCopy := doRequest(req, dst, url, c)
|
||||
ch <- clientURLResponse{
|
||||
statusCode: statusCodeCopy,
|
||||
body: bodyCopy,
|
||||
err: errCopy,
|
||||
}
|
||||
}()
|
||||
|
||||
var tc *time.Timer
|
||||
tcv := timerPool.Get()
|
||||
if tcv == nil {
|
||||
tc = time.NewTimer(timeout)
|
||||
tcv = tc
|
||||
} else {
|
||||
tc = tcv.(*time.Timer)
|
||||
initTimer(tc, timeout)
|
||||
}
|
||||
|
||||
select {
|
||||
case err = <-ch:
|
||||
case resp := <-ch:
|
||||
releaseRequest(req)
|
||||
errorChPool.Put(chv)
|
||||
statusCode = statusCodeCopy
|
||||
body = bodyCopy
|
||||
statusCode = resp.statusCode
|
||||
body = resp.body
|
||||
err = resp.err
|
||||
case <-tc.C:
|
||||
body = dst
|
||||
err = ErrTimeout
|
||||
@@ -625,10 +633,9 @@ func clientDoTimeoutFreeConn(req *Request, resp *Response, timeout time.Duration
|
||||
var ch chan error
|
||||
chv := errorChPool.Get()
|
||||
if chv == nil {
|
||||
ch = make(chan error, 1)
|
||||
} else {
|
||||
ch = chv.(chan error)
|
||||
chv = make(chan error, 1)
|
||||
}
|
||||
ch = chv.(chan error)
|
||||
|
||||
// Make req and resp copies, since on timeout they no longer
|
||||
// may be accessed.
|
||||
@@ -651,6 +658,7 @@ func clientDoTimeoutFreeConn(req *Request, resp *Response, timeout time.Duration
|
||||
tcv := timerPool.Get()
|
||||
if tcv == nil {
|
||||
tc = time.NewTimer(timeout)
|
||||
tcv = tc
|
||||
} else {
|
||||
tc = tcv.(*time.Timer)
|
||||
initTimer(tc, timeout)
|
||||
|
||||
+32
-2
@@ -69,7 +69,37 @@ func acquireFakeServerConn(s []byte) *fakeClientConn {
|
||||
|
||||
var fakeClientConnPool sync.Pool
|
||||
|
||||
func BenchmarkClientGetFastServer(b *testing.B) {
|
||||
func BenchmarkClientGetTimeoutFastServer(b *testing.B) {
|
||||
body := []byte("123456789099")
|
||||
s := []byte(fmt.Sprintf("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %d\r\n\r\n%s", len(body), body))
|
||||
c := &Client{
|
||||
Dial: func(addr string) (net.Conn, error) {
|
||||
return acquireFakeServerConn(s), nil
|
||||
},
|
||||
}
|
||||
|
||||
nn := uint32(0)
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
url := fmt.Sprintf("http://foobar%d.com/aaa/bbb", atomic.AddUint32(&nn, 1))
|
||||
var statusCode int
|
||||
var bodyBuf []byte
|
||||
var err error
|
||||
for pb.Next() {
|
||||
statusCode, bodyBuf, err = c.GetTimeout(bodyBuf[:0], url, time.Second)
|
||||
if err != nil {
|
||||
b.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
if statusCode != StatusOK {
|
||||
b.Fatalf("unexpected status code: %d", statusCode)
|
||||
}
|
||||
if !bytes.Equal(bodyBuf, body) {
|
||||
b.Fatalf("unexpected response body: %q. Expected %q", bodyBuf, body)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkClientDoFastServer(b *testing.B) {
|
||||
body := []byte("012345678912")
|
||||
s := []byte(fmt.Sprintf("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %d\r\n\r\n%s", len(body), body))
|
||||
c := &Client{
|
||||
@@ -97,7 +127,7 @@ func BenchmarkClientGetFastServer(b *testing.B) {
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkNetHTTPClientGetFastServer(b *testing.B) {
|
||||
func BenchmarkNetHTTPClientDoFastServer(b *testing.B) {
|
||||
body := []byte("012345678912")
|
||||
s := []byte(fmt.Sprintf("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %d\r\n\r\n%s", len(body), body))
|
||||
c := &http.Client{
|
||||
|
||||
Reference in New Issue
Block a user