mirror of
https://github.com/lukaszraczylo/go-telegram.git
synced 2026-06-10 23:09:04 +00:00
perf(client): pool *bytes.Buffer for response body reads
Replace io.ReadAll(resp.Body) on the typed Call/callMultipart paths with a sync.Pool-backed bytes.Buffer + ReadFrom. Saves the 512B initial allocation that ReadAll grows from on every successful call. The pool only covers paths whose decoder copies strings out of the input (decodeResult delegates to goccy/go-json, which copies). CallRaw and callMultipartRaw return slices that alias the buffer storage, so they keep the io.ReadAll path; pooling there would need a defensive copy that defeats the saving. putRespBuf caps Cap() at 64 KiB before returning to the pool so a single oversized response (e.g. large getFile metadata) doesn't bloat the pool for the rest of the process. Bench delta on Call_BoolResponse: 14 allocs -> 13 allocs, 1842B -> 1331B, 526ns -> 479ns. Same shape on Call_StructResponse (16 -> 15, 1973B -> 1462B).
This commit is contained in:
+6
-3
@@ -1,6 +1,7 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"github.com/goccy/go-json"
|
||||
"io"
|
||||
@@ -81,12 +82,14 @@ func callMultipart[Resp any](ctx context.Context, b *Bot, method string, mp mult
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
|
||||
raw, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
buf := respBufPool.Get().(*bytes.Buffer)
|
||||
buf.Reset()
|
||||
defer putRespBuf(buf)
|
||||
if _, err := buf.ReadFrom(resp.Body); err != nil {
|
||||
_ = pr.CloseWithError(err)
|
||||
return zero, &NetworkError{Err: err}
|
||||
}
|
||||
return decodeResult[Resp](b.codec, raw)
|
||||
return decodeResult[Resp](b.codec, buf.Bytes())
|
||||
}
|
||||
|
||||
// callMultipartRaw is callMultipart's sibling that returns the raw result
|
||||
|
||||
Reference in New Issue
Block a user