-
Notifications
You must be signed in to change notification settings - Fork 17.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
net/http: reuse gzip reader from pool for transport #61353
Comments
Hmm. func (gz *gzipReader) Read(p []byte) (n int, err error) {
gz.body.mu.Lock()
if gz.body.closed {
err = errReadOnClosedResBody
} else if gz.zr == nil {
if gz.zerr == nil {
zr := gzipPool.Get().(*gzip.Reader)
gz.zerr = zr.Reset(gz.body)
if gz.zerr == nil {
gz.zr = zr
} else {
gzipPool.Put(zr)
}
}
err = gz.zerr
}
gz.body.mu.Unlock()
if err != nil {
return 0, err
}
return gz.zr.Read(p)
}
func (gz *gzipReader) Close() error {
err := gz.body.Close()
gz.body.mu.Lock()
if gz.zr != nil {
gz.zr.Reset(emptyReader{}) // drop reference to gz.body
gzipPool.Put(gz.zr)
gz.zr = nil
}
gz.body.mu.Unlock()
return err
}
var (
gzipPool = sync.Pool{
New: func() any { return new(gzip.Reader) },
}
_ flate.Reader = emptyReader{}
)
type emptyReader struct{}
func (emptyReader) Read([]byte) (int, error) { return 0, io.EOF }
func (emptyReader) ReadByte() (byte, error) { return 0, io.EOF } Of course, such a change would also need a supporting benchmark. @Sunyue, want to send it for Go 1.22? (CC @neild) |
Seems like something we could do; I'm happy to review a CL if someone wants to send me one. |
name old time/op new time/op delta GzipReaderInit-8 9.15µs ± 4% 2.38µs ± 9% -74.04% (p=0.000 n=10+10) name old alloc/op new alloc/op delta GzipReaderInit-8 45.5kB ± 0% 4.3kB ± 0% -90.47% (p=0.000 n=10+10) name old allocs/op new allocs/op delta GzipReaderInit-8 10.0 ± 0% 5.0 ± 0% -50.00% (p=0.000 n=10+10) Allocation saving comes from absent compress/flate.(*dictDecoder).init Fixes golang#61353
Change https://go.dev/cl/510115 mentions this issue: |
name old time/op new time/op delta GzipReaderInit-8 8.97µs ± 6% 2.61µs ± 7% -70.87% (p=0.000 n=10+9) name old alloc/op new alloc/op delta GzipReaderInit-8 45.5kB ± 0% 4.4kB ± 0% -90.36% (p=0.000 n=10+10) name old allocs/op new allocs/op delta GzipReaderInit-8 10.0 ± 0% 6.0 ± 0% -40.00% (p=0.000 n=10+10) Allocation saving comes from absent compress/flate.(*dictDecoder).init Fixes golang#61353
Change https://go.dev/cl/510255 mentions this issue: |
name old time/op new time/op delta GzipReaderInit-8 8.97µs ± 6% 2.61µs ± 7% -70.87% (p=0.000 n=10+9) name old alloc/op new alloc/op delta GzipReaderInit-8 45.5kB ± 0% 4.4kB ± 0% -90.36% (p=0.000 n=10+10) name old allocs/op new allocs/op delta GzipReaderInit-8 10.0 ± 0% 6.0 ± 0% -40.00% (p=0.000 n=10+10) Allocation saving comes from absent compress/flate.(*dictDecoder).init Fixes golang#61353
Created #61390 |
│ old │ new │ │ sec/op │ sec/op vs base │ GzipReaderInit-8 8.940µ ± 4% 2.532µ ± 8% -71.68% (p=0.000 n=10) │ old │ new │ │ B/op │ B/op vs base │ GzipReaderInit-8 44.438Ki ± 0% 4.297Ki ± 0% -90.33% (p=0.000 n=10) │ old │ new │ │ allocs/op │ allocs/op vs base │ GzipReaderInit-8 10.000 ± 0% 6.000 ± 0% -40.00% (p=0.000 n=10) Allocation saving comes from absent compress/flate.(*dictDecoder).init Updates golang#61353
│ old │ new │ │ sec/op │ sec/op vs base │ GzipReaderInit-8 8.854µ ± 5% 2.578µ ± 16% -70.89% (p=0.000 n=10) │ old │ new │ │ B/op │ B/op vs base │ GzipReaderInit-8 44.438Ki ± 0% 4.282Ki ± 0% -90.36% (p=0.000 n=10) │ old │ new │ │ allocs/op │ allocs/op vs base │ GzipReaderInit-8 10.000 ± 0% 6.000 ± 0% -40.00% (p=0.000 n=10) Allocation saving comes from absent compress/flate.(*dictDecoder).init Updates golang#61353
│ old │ new │ │ sec/op │ sec/op vs base │ GzipReaderInit-8 8.854µ ± 5% 2.578µ ± 16% -70.89% (p=0.000 n=10) │ old │ new │ │ B/op │ B/op vs base │ GzipReaderInit-8 44.438Ki ± 0% 4.282Ki ± 0% -90.36% (p=0.000 n=10) │ old │ new │ │ allocs/op │ allocs/op vs base │ GzipReaderInit-8 10.000 ± 0% 6.000 ± 0% -40.00% (p=0.000 n=10) Allocation saving comes from absent compress/flate.(*dictDecoder).init Updates golang#61353
│ old │ new │ │ sec/op │ sec/op vs base │ GzipReaderInit-8 8.891µ ± 10% 2.570µ ± 8% -71.10% (p=0.000 n=10) │ old │ new │ │ B/op │ B/op vs base │ GzipReaderInit-8 44.438Ki ± 0% 4.282Ki ± 0% -90.36% (p=0.000 n=10) │ old │ new │ │ allocs/op │ allocs/op vs base │ GzipReaderInit-8 10.000 ± 0% 6.000 ± 0% -40.00% (p=0.000 n=10) Allocation saving comes from absent compress/flate.(*dictDecoder).init Updates golang#61353
│ old │ new │ │ sec/op │ sec/op vs base │ GzipReaderInit-8 8.854µ ± 5% 2.578µ ± 16% -70.89% (p=0.000 n=10) │ old │ new │ │ B/op │ B/op vs base │ GzipReaderInit-8 44.438Ki ± 0% 4.282Ki ± 0% -90.36% (p=0.000 n=10) │ old │ new │ │ allocs/op │ allocs/op vs base │ GzipReaderInit-8 10.000 ± 0% 6.000 ± 0% -40.00% (p=0.000 n=10) Allocation saving comes from absent compress/flate.(*dictDecoder).init Updates golang#61353
│ old │ new │ │ sec/op │ sec/op vs base │ ClientGzip-8 649.4µ ± 4% 644.4µ ± 12% ~ (p=0.739 n=10) │ old │ new │ │ B/op │ B/op vs base │ ClientGzip-8 49.486Ki ± 0% 9.270Ki ± 2% -81.27% (p=0.000 n=10) │ old │ new │ │ allocs/op │ allocs/op vs base │ ClientGzip-8 51.00 ± 0% 46.00 ± 0% -9.80% (p=0.000 n=10) Allocation saving comes from absent compress/flate.(*dictDecoder).init Updates golang#61353
│ old │ new │ │ sec/op │ sec/op vs base │ ClientGzip-8 649.4µ ± 4% 644.4µ ± 12% ~ (p=0.739 n=10) │ old │ new │ │ B/op │ B/op vs base │ ClientGzip-8 49.486Ki ± 0% 9.270Ki ± 2% -81.27% (p=0.000 n=10) │ old │ new │ │ allocs/op │ allocs/op vs base │ ClientGzip-8 51.00 ± 0% 46.00 ± 0% -9.80% (p=0.000 n=10) Allocation saving comes from absent compress/flate.(*dictDecoder).init Updates golang#61353
│ old │ new │ │ sec/op │ sec/op vs base │ ClientGzip-8 649.4µ ± 4% 644.4µ ± 12% ~ (p=0.739 n=10) │ old │ new │ │ B/op │ B/op vs base │ ClientGzip-8 49.486Ki ± 0% 9.270Ki ± 2% -81.27% (p=0.000 n=10) │ old │ new │ │ allocs/op │ allocs/op vs base │ ClientGzip-8 51.00 ± 0% 46.00 ± 0% -9.80% (p=0.000 n=10) Allocation saving comes from absent compress/flate.(*dictDecoder).init Updates golang#61353
│ old │ new │ │ sec/op │ sec/op vs base │ ClientGzip-8 649.4µ ± 4% 644.4µ ± 12% ~ (p=0.739 n=10) │ old │ new │ │ B/op │ B/op vs base │ ClientGzip-8 49.486Ki ± 0% 9.270Ki ± 2% -81.27% (p=0.000 n=10) │ old │ new │ │ allocs/op │ allocs/op vs base │ ClientGzip-8 51.00 ± 0% 46.00 ± 0% -9.80% (p=0.000 n=10) Allocation saving comes from absent compress/flate.(*dictDecoder).init Updates golang#61353
goos: linux goarch: amd64 pkg: net/http │ /tmp/BenchmarkClientGzip.old │ /tmp/BenchmarkClientGzip.new │ │ sec/op │ sec/op vs base │ ClientGzip-8 509.6µ ± 7% 545.5µ ± 10% ~ (p=0.218 n=10) │ /tmp/BenchmarkClientGzip.old │ /tmp/BenchmarkClientGzip.new │ │ B/op │ B/op vs base │ ClientGzip-8 48.943Ki ± 0% 8.757Ki ± 1% -82.11% (p=0.000 n=10) │ /tmp/BenchmarkClientGzip.old │ /tmp/BenchmarkClientGzip.new │ │ allocs/op │ allocs/op vs base │ ClientGzip-8 51.00 ± 0% 46.00 ± 0% -9.80% (p=0.000 n=10) Allocation saving comes from absent compress/flate.(*dictDecoder).init Updates golang#61353
goos: linux goarch: amd64 pkg: net/http │ /tmp/BenchmarkClientGzip.old │ /tmp/BenchmarkClientGzip.new │ │ sec/op │ sec/op vs base │ ClientGzip-8 509.6µ ± 7% 545.5µ ± 10% ~ (p=0.218 n=10) │ /tmp/BenchmarkClientGzip.old │ /tmp/BenchmarkClientGzip.new │ │ B/op │ B/op vs base │ ClientGzip-8 48.943Ki ± 0% 8.757Ki ± 1% -82.11% (p=0.000 n=10) │ /tmp/BenchmarkClientGzip.old │ /tmp/BenchmarkClientGzip.new │ │ allocs/op │ allocs/op vs base │ ClientGzip-8 51.00 ± 0% 46.00 ± 0% -9.80% (p=0.000 n=10) Allocation saving comes from absent compress/flate.(*dictDecoder).init Updates golang#61353
go/src/net/http/transport.go
Line 2858 in 089e37a
Is it possible to reuse this gzip reader from a
sync.Pool
to reduce the memory allocation cause byflate.NewReader
The text was updated successfully, but these errors were encountered: