diff options
| author | korzhao <korzhao95@gmail.com> | 2023-08-11 17:20:36 +0800 |
|---|---|---|
| committer | Daniel Martí <mvdan@mvdan.cc> | 2023-08-25 08:50:27 +0000 |
| commit | ddad9b618cce0ed91d66f0470ddb3e12cfd7eeac (patch) | |
| tree | 4b81947a5fb2f60bffe7abdc83ea2aac6552f095 /src/encoding/json/decode.go | |
| parent | 4c5dac72029bb3dd4559a2fafe566bed71f22c42 (diff) | |
| download | go-ddad9b618cce0ed91d66f0470ddb3e12cfd7eeac.tar.xz | |
encoding/json: avoid allocation when decoding number types
In CL 345488, we optimized strconv.ParseXXX for []byte arguments.
That allows immediate casting of a []byte to a string that does not escape to be copied on the stack.
Performance:
goos: darwin
goarch: arm64
pkg: encoding/json
old sec/op new sec/op delta
CodeUnmarshal-10 3.019m ± 6% 2.865m ± 10% -5.10% (p=0.043 n=10)
CodeUnmarshalReuse-10 2.528m ± 4% 2.274m ± 13% -10.03% (p=0.009 n=10)
geomean 2.762m 2.553m -7.60%
old B/s new B/s delta
CodeUnmarshal-10 613.1Mi ± 5% 646.0Mi ± 9% +5.37% (p=0.043 n=10)
CodeUnmarshalReuse-10 732.1Mi ± 4% 813.7Mi ± 12% +11.15% (p=0.009 n=10)
geomean 669.9Mi 725.0Mi +8.22%
old B/op new B/op delta
CodeUnmarshal-10 2.782Mi ± 0% 1.918Mi ± 0% -31.04% (p=0.000 n=10)
CodeUnmarshalReuse-10 1600.8Ki ± 0% 713.3Ki ± 0% -55.44% (p=0.000 n=10)
geomean 2.085Mi 1.156Mi -44.57%
old allocs/op new allocs/op delta
CodeUnmarshal-10 91.31k ± 0% 39.99k ± 0% -56.20% (p=0.000 n=10)
CodeUnmarshalReuse-10 76.58k ± 0% 25.23k ± 0% -67.06% (p=0.000 n=10)
geomean 83.62k 31.76k -62.02%
Change-Id: I208c57089040daee0f9d979d1df725e3acf34f81
Reviewed-on: https://go-review.googlesource.com/c/go/+/518277
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Joseph Tsai <joetsai@digital-static.net>
Run-TryBot: Joseph Tsai <joetsai@digital-static.net>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Diffstat (limited to 'src/encoding/json/decode.go')
| -rw-r--r-- | src/encoding/json/decode.go | 17 |
1 files changed, 8 insertions, 9 deletions
diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go index 858a2ed41a..72188a66f6 100644 --- a/src/encoding/json/decode.go +++ b/src/encoding/json/decode.go @@ -962,13 +962,12 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool } panic(phasePanicMsg) } - s := string(item) switch v.Kind() { default: if v.Kind() == reflect.String && v.Type() == numberType { // s must be a valid number, because it's // already been tokenized. - v.SetString(s) + v.SetString(string(item)) break } if fromQuoted { @@ -976,7 +975,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool } d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) case reflect.Interface: - n, err := d.convertNumber(s) + n, err := d.convertNumber(string(item)) if err != nil { d.saveError(err) break @@ -988,25 +987,25 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool v.Set(reflect.ValueOf(n)) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - n, err := strconv.ParseInt(s, 10, 64) + n, err := strconv.ParseInt(string(item), 10, 64) if err != nil || v.OverflowInt(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())}) break } v.SetInt(n) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - n, err := strconv.ParseUint(s, 10, 64) + n, err := strconv.ParseUint(string(item), 10, 64) if err != nil || v.OverflowUint(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())}) break } v.SetUint(n) case reflect.Float32, reflect.Float64: - n, err := strconv.ParseFloat(s, v.Type().Bits()) + n, err := strconv.ParseFloat(string(item), v.Type().Bits()) if err != nil || v.OverflowFloat(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())}) break } v.SetFloat(n) |
