mirror of
https://github.com/golang/go.git
synced 2025-11-09 05:01:01 +00:00
encoding/gob: speed up encoding of arrays and slices
We borrow a trick from the fmt package and avoid reflection to walk the elements when possible. We could push further with unsafe (and we may) but this is a good start. Decode can benefit similarly; it will be done separately. Use go generate (engen.go) to produce the helper functions (enc_helpers.go). benchmark old ns/op new ns/op delta BenchmarkEndToEndPipe 6593 6482 -1.68% BenchmarkEndToEndByteBuffer 3662 3684 +0.60% BenchmarkEndToEndSliceByteBuffer 350306 351693 +0.40% BenchmarkComplex128Slice 96347 80045 -16.92% BenchmarkInt32Slice 42484 26008 -38.78% BenchmarkFloat64Slice 51143 36265 -29.09% BenchmarkStringSlice 53402 35077 -34.32% LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/156310043
This commit is contained in:
parent
fb173c4185
commit
5e713062b4
4 changed files with 708 additions and 3 deletions
|
|
@ -2,6 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run encgen.go -output enc_helpers.go
|
||||
|
||||
package gob
|
||||
|
||||
import (
|
||||
|
|
@ -13,6 +15,8 @@ import (
|
|||
|
||||
const uint64Size = 8
|
||||
|
||||
type encHelper func(state *encoderState, v reflect.Value) bool
|
||||
|
||||
// encoderState is the global execution state of an instance of the encoder.
|
||||
// Field numbers are delta encoded and always increase. The field
|
||||
// number is initialized to -1 so 0 comes out as delta(1). A delta of
|
||||
|
|
@ -291,12 +295,15 @@ func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, value refle
|
|||
}
|
||||
|
||||
// encodeArray encodes an array.
|
||||
func (enc *Encoder) encodeArray(b *bytes.Buffer, value reflect.Value, op encOp, elemIndir int, length int) {
|
||||
func (enc *Encoder) encodeArray(b *bytes.Buffer, value reflect.Value, op encOp, elemIndir int, length int, helper encHelper) {
|
||||
state := enc.newEncoderState(b)
|
||||
defer enc.freeEncoderState(state)
|
||||
state.fieldnum = -1
|
||||
state.sendZero = true
|
||||
state.encodeUint(uint64(length))
|
||||
if helper != nil && helper(state, value) {
|
||||
return
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
elem := value.Index(i)
|
||||
if elemIndir > 0 {
|
||||
|
|
@ -501,19 +508,21 @@ func encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp, building map[
|
|||
}
|
||||
// Slices have a header; we decode it to find the underlying array.
|
||||
elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building)
|
||||
helper := sliceHelper[t.Elem().Kind()]
|
||||
op = func(i *encInstr, state *encoderState, slice reflect.Value) {
|
||||
if !state.sendZero && slice.Len() == 0 {
|
||||
return
|
||||
}
|
||||
state.update(i)
|
||||
state.enc.encodeArray(state.b, slice, *elemOp, elemIndir, slice.Len())
|
||||
state.enc.encodeArray(state.b, slice, *elemOp, elemIndir, slice.Len(), helper)
|
||||
}
|
||||
case reflect.Array:
|
||||
// True arrays have size in the type.
|
||||
elemOp, elemIndir := encOpFor(t.Elem(), inProgress, building)
|
||||
helper := arrayHelper[t.Elem().Kind()]
|
||||
op = func(i *encInstr, state *encoderState, array reflect.Value) {
|
||||
state.update(i)
|
||||
state.enc.encodeArray(state.b, array, *elemOp, elemIndir, array.Len())
|
||||
state.enc.encodeArray(state.b, array, *elemOp, elemIndir, array.Len(), helper)
|
||||
}
|
||||
case reflect.Map:
|
||||
keyOp, keyIndir := encOpFor(t.Key(), inProgress, building)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue