mirror of
https://github.com/golang/go
synced 2024-11-22 22:40:02 -07:00
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
This commit is contained in:
parent
d73452b30f
commit
f1583bb956
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user