Commit f1583bb9 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

encoding/json: allocate less in NewEncoder

The *Encoder is almost always garbage. It doesn't need an
encodeState inside of it (and its bytes.Buffer), since it's
only needed locally inside of Encode.

benchmark                 old ns/op    new ns/op    delta
BenchmarkEncoderEncode         2562         2553   -0.35%

benchmark                 old bytes    new bytes    delta
BenchmarkEncoderEncode          283          102  -63.96%

R=r
CC=gobot, golang-dev
https://golang.org/cl/9365044
parent d73452b3
...@@ -227,6 +227,26 @@ type encodeState struct { ...@@ -227,6 +227,26 @@ type encodeState struct {
scratch [64]byte scratch [64]byte
} }
// TODO(bradfitz): use a sync.Cache here
var encodeStatePool = make(chan *encodeState, 8)
func newEncodeState() *encodeState {
select {
case e := <-encodeStatePool:
e.Reset()
return e
default:
return new(encodeState)
}
}
func putEncodeState(e *encodeState) {
select {
case encodeStatePool <- e:
default:
}
}
func (e *encodeState) marshal(v interface{}) (err error) { func (e *encodeState) marshal(v interface{}) (err error) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
......
...@@ -156,8 +156,8 @@ func (enc *Encoder) Encode(v interface{}) error { ...@@ -156,8 +156,8 @@ func (enc *Encoder) Encode(v interface{}) error {
if enc.err != nil { if enc.err != nil {
return enc.err return enc.err
} }
enc.e.Reset() e := newEncodeState()
err := enc.e.marshal(v) err := e.marshal(v)
if err != nil { if err != nil {
return err return err
} }
...@@ -168,11 +168,12 @@ func (enc *Encoder) Encode(v interface{}) error { ...@@ -168,11 +168,12 @@ func (enc *Encoder) Encode(v interface{}) error {
// is required if the encoded value was a number, // is required if the encoded value was a number,
// so that the reader knows there aren't more // so that the reader knows there aren't more
// digits coming. // digits coming.
enc.e.WriteByte('\n') e.WriteByte('\n')
if _, err = enc.w.Write(enc.e.Bytes()); err != nil { if _, err = enc.w.Write(e.Bytes()); err != nil {
enc.err = err enc.err = err
} }
putEncodeState(e)
return err return err
} }
......
...@@ -191,3 +191,16 @@ func TestBlocking(t *testing.T) { ...@@ -191,3 +191,16 @@ func TestBlocking(t *testing.T) {
w.Close() w.Close()
} }
} }
func BenchmarkEncoderEncode(b *testing.B) {
b.ReportAllocs()
type T struct {
X, Y string
}
v := &T{"foo", "bar"}
for i := 0; i < b.N; i++ {
if err := NewEncoder(ioutil.Discard).Encode(v); err != nil {
b.Fatal(err)
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment