]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/json: allocate less in NewEncoder
authorBrad Fitzpatrick <bradfitz@golang.org>
Tue, 14 May 2013 22:50:46 +0000 (15:50 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Tue, 14 May 2013 22:50:46 +0000 (15:50 -0700)
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

src/pkg/encoding/json/encode.go
src/pkg/encoding/json/stream.go
src/pkg/encoding/json/stream_test.go

index 85727ba61c0806b24aafac197a9a5982366a513e..ffe903a546b4c24b22700c4b79f5c32fe5fcd9cb 100644 (file)
@@ -227,6 +227,26 @@ type encodeState struct {
        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) {
        defer func() {
                if r := recover(); r != nil {
index 00f4726cf7f6dce09cbda73c271eeea1babad756..67f6be87b2196a609f203cd2421b2e8d651e9c71 100644 (file)
@@ -156,8 +156,8 @@ func (enc *Encoder) Encode(v interface{}) error {
        if enc.err != nil {
                return enc.err
        }
-       enc.e.Reset()
-       err := enc.e.marshal(v)
+       e := newEncodeState()
+       err := e.marshal(v)
        if err != nil {
                return err
        }
@@ -168,11 +168,12 @@ func (enc *Encoder) Encode(v interface{}) error {
        // is required if the encoded value was a number,
        // so that the reader knows there aren't more
        // 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
        }
+       putEncodeState(e)
        return err
 }
 
index 07c9e1d390c68db75a19a88a120d60e981594387..b562e87690d5ee9b140b8a9de9e68308bae9407a 100644 (file)
@@ -191,3 +191,16 @@ func TestBlocking(t *testing.T) {
                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)
+               }
+       }
+}