]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/json: improve performance of Unmarshal on primitive types
authorRick Arnold <rickarnoldjr@gmail.com>
Thu, 31 Jan 2013 01:53:48 +0000 (17:53 -0800)
committerRuss Cox <rsc@golang.org>
Thu, 31 Jan 2013 01:53:48 +0000 (17:53 -0800)
Attempt 2. The first fix was much faster but ignored syntax errors.

benchmark                      old ns/op    new ns/op    delta
BenchmarkCodeEncoder            74993543     72982390   -2.68%
BenchmarkCodeMarshal            77811181     75610637   -2.83%
BenchmarkCodeDecoder           213337123    190144982  -10.87%
BenchmarkCodeUnmarshal         212180972    190394852  -10.27%
BenchmarkCodeUnmarshalReuse    202113428    182106660   -9.90%
BenchmarkUnmarshalString            1343          919  -31.57%
BenchmarkUnmarshalFloat64           1149          908  -20.97%
BenchmarkUnmarshalInt64              967          778  -19.54%
BenchmarkSkipValue              28851581     28414125   -1.52%

benchmark                       old MB/s     new MB/s  speedup
BenchmarkCodeEncoder               25.88        26.59    1.03x
BenchmarkCodeMarshal               24.94        25.66    1.03x
BenchmarkCodeDecoder                9.10        10.21    1.12x
BenchmarkCodeUnmarshal              9.15        10.19    1.11x
BenchmarkSkipValue                 69.05        70.11    1.02x

Fixes #3949.

R=rsc
CC=golang-dev
https://golang.org/cl/7231058

src/pkg/encoding/json/decode.go

index e6e15b00d677c4ef076f7f2c637b889c795905ff..6109450221864e29988f846f00505a87724e39eb 100644 (file)
@@ -52,16 +52,34 @@ import (
 // an UnmarshalTypeError describing the earliest such error.
 //
 func Unmarshal(data []byte, v interface{}) error {
-       d := new(decodeState).init(data)
 
        // Quick check for well-formedness.
        // Avoids filling out half a data structure
        // before discovering a JSON syntax error.
+       var d decodeState
        err := checkValid(data, &d.scan)
        if err != nil {
                return err
        }
 
+       // skip heavy processing for primitive values
+       var first byte
+       var i int
+       for i, first = range data {
+               if first > ' ' || !isSpace(rune(first)) {
+                       break
+               }
+       }
+       if first != '{' && first != '[' {
+               rv := reflect.ValueOf(v)
+               if rv.Kind() != reflect.Ptr || rv.IsNil() {
+                       return &InvalidUnmarshalError{reflect.TypeOf(v)}
+               }
+               d.literalStore(data[i:], rv.Elem(), false)
+               return d.savedError
+       }
+
+       d.init(data)
        return d.unmarshal(v)
 }