fastjson
fastjson copied to clipboard
Parse without making a copy
Currently, Parser.Parse
and Parser.ParseBytes
are making a copy of the argument and then modify it.
I have a case where I already pass a copy which can be modified directly. It would be nice to have an API for that.
This optimization shouldn't give significant win:
$ GOMAXPROCS=1 go test github.com/valyala/fastjson -run=111 -bench=Parse$/large/fastjson$ -benchtime=10s -cpuprofile=cpu.pprof
$ go tool pprof cpu.pprof
(pprof) list Parse$
ROUTINE ======================== github.com/valyala/fastjson.(*Parser).Parse in /home/valyala/go/src/github.com/valyala/fastjson/parser.go
10ms 24.93s (flat, cum) 100% of Total
. . 26:// The returned value is valid until the next call to Parse*.
. . 27://
. . 28:// Use Scanner if a stream of JSON values must be parsed.
. . 29:func (p *Parser) Parse(s string) (*Value, error) {
. . 30: s = skipWS(s)
10ms 530ms 31: p.b = append(p.b[:0], s...)
. . 32: p.c.reset()
. . 33:
. 24.39s 34: v, tail, err := parseValue(b2s(p.b), &p.c)
. . 35: if err != nil {
. . 36: return nil, fmt.Errorf("cannot parse JSON: %s; unparsed tail: %q", err, tail)
. . 37: }
. 10ms 38: tail = skipWS(tail)
. . 39: if len(tail) > 0 {
. . 40: return nil, fmt.Errorf("unexpected tail: %q", tail)
. . 41: }
. . 42: return v, nil
. . 43:}
The copying takes only 0.5 seconds out of 25 seconds spent in Parse
, i.e. 2%. So this optimization would improve performance only by 2% at the cost of more fragile code. Do you have another numbers?