From 1b0d04b89fa12bf635467e0ef7acff3fcc78d208 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 28 Mar 2013 14:51:21 -0700 Subject: [PATCH] net/http: reuse textproto.Readers; remove 2 more allocations Saves both the textproto.Reader allocation, and its internal scratch buffer growing. benchmark old ns/op new ns/op delta BenchmarkServerFakeConnWithKeepAliveLite 10324 10149 -1.70% benchmark old allocs new allocs delta BenchmarkServerFakeConnWithKeepAliveLite 19 17 -10.53% benchmark old bytes new bytes delta BenchmarkServerFakeConnWithKeepAliveLite 1559 1492 -4.30% R=golang-dev, r, gri CC=golang-dev https://golang.org/cl/8094046 --- src/pkg/net/http/request.go | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/pkg/net/http/request.go b/src/pkg/net/http/request.go index b42cc58a49..c1f862aadd 100644 --- a/src/pkg/net/http/request.go +++ b/src/pkg/net/http/request.go @@ -478,10 +478,31 @@ func parseRequestLine(line string) (method, requestURI, proto string, ok bool) { return line[:s1], line[s1+1 : s2], line[s2+1:], true } +// TODO(bradfitz): use a sync.Cache when available +var textprotoReaderCache = make(chan *textproto.Reader, 4) + +func newTextprotoReader(br *bufio.Reader) *textproto.Reader { + select { + case r := <-textprotoReaderCache: + r.R = br + return r + default: + return textproto.NewReader(br) + } +} + +func putTextprotoReader(r *textproto.Reader) { + r.R = nil + select { + case textprotoReaderCache <- r: + default: + } +} + // ReadRequest reads and parses a request from b. func ReadRequest(b *bufio.Reader) (req *Request, err error) { - tp := textproto.NewReader(b) + tp := newTextprotoReader(b) req = new(Request) // First line: GET /index.html HTTP/1.0 @@ -490,6 +511,7 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) { return nil, err } defer func() { + putTextprotoReader(tp) if err == io.EOF { err = io.ErrUnexpectedEOF }