Re: [go-nuts] Python simplejson is 5x faster than Go encoding/json

2,631 views
Skip to first unread message

Robert Melton

unread,
Dec 26, 2013, 12:44:13 AM12/26/13
to Xun Liu, golang-nuts
On Wed, Dec 25, 2013 at 8:08 PM, Xun Liu <pas...@gmail.com> wrote:
> I'm in the process of converting some Python code into Go. Since Json
> encoding/decoding is one of the most common operations in the code so I did
> some simple json benchmarking for two packages.

What % of the work time of your program is spent doing json encoding /
decoding? As a percentage, as profiled, is this one of your hotspots?


> simplejson takes 18ms to decode the json string for 1000 times while Go
> takes 99ms.
> simplejson takes 32ms to encode the object and go takes 82ms.

I suspect you are actually using the C extension to simplejson (it is
the default), so this isn't so much comparing Go to Python ... as Go
to C.

When we looked at this comparison (some time ago) we found Go's JSON
to be 3x to 4x slower than simplejson. Seems like the ratio is
roughly the same.

While this isn't what we wanted, it was so far from a choke point in
our code it really functioned as nothing more than a bit of trivia.
Benchmarks are fun, but is the json marshall/unmarshall even in the
top 10 hotspots in your code? It wasn't even in our top 25 when
profiled.


> Any pointers on how to improve Go's json performance are appreciated.

Don't. Premature optimization. Are the fraction of a milisecond that
the encoding / decoding take per really what need to be optimized in
your code? Have you profiled at all?

--
Robert Melton

Rémy Oudompheng

unread,
Dec 26, 2013, 2:30:15 AM12/26/13
to Xun Liu, golang-nuts
On 2013/12/26 Xun Liu <pas...@gmail.com> wrote:
>
> I'm in the process of converting some Python code into Go. Since Json
> encoding/decoding is one of the most common operations in the code so I did
> some simple json benchmarking for two packages. The benchmark is really
> simple: it decodes a json string 1000 times, and encodes it 1000 times. The
> results are:
>
> 1. simplejson is 5x faster than encoding/json in decoding.
> 2. simplejson is 2-3x faster than encoding/json in encoding.

This issue is tracked by http://golang.org/issue/5683

> Any pointers on how to improve Go's json performance are appreciated.

Patches will be appreciated.

Rémy.

Xun Liu

unread,
Dec 26, 2013, 6:21:37 AM12/26/13
to Robert Melton, golang-nuts
On Wed, Dec 25, 2013 at 9:44 PM, Robert Melton <rob...@robertmelton.com> wrote:
On Wed, Dec 25, 2013 at 8:08 PM, Xun Liu <pas...@gmail.com> wrote:
> I'm in the process of converting some Python code into Go. Since Json
> encoding/decoding is one of the most common operations in the code so I did
> some simple json benchmarking for two packages.

What % of the work time of your program is spent doing json encoding /
decoding?  As a percentage, as profiled, is this one of your hotspots?


Roughly 30%. If I can get it to simplejson performance level, it means 20-25% speed up of my program. It' a big win for me.

Dave Cheney

unread,
Dec 26, 2013, 6:25:29 AM12/26/13
to Xun Liu, Robert Melton, golang-nuts
You may wish to investigate this alternative json implementation.

https://github.com/benbjohnson/megajson
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.

Matt Reiferson

unread,
Dec 26, 2013, 12:42:03 PM12/26/13
to Dave Cheney, Xun Liu, Robert Melton, golang-nuts
Also, I haven’t finished cleaning this up yet… but I ported ujson to Go with decent results so far:


This is only the decode side, though.

Jens Alfke

unread,
Dec 26, 2013, 8:51:33 PM12/26/13
to golan...@googlegroups.com, Xun Liu, rob...@robertmelton.com


On Wednesday, December 25, 2013 9:44:13 PM UTC-8, Robert Melton wrote:
> Any pointers on how to improve Go's json performance are appreciated.

Don't.  Premature optimization.  Are the fraction of a milisecond that
the encoding / decoding take per really what need to be optimized in
your code?  Have you profiled at all?

This is premature admonition of premature optimization. How do you know that JSON encoding isn't really a hot spot? Isn't it better to give the OP the benefit of the doubt rather than talk down to him?

In my own application the JSON codec has frequently been a bottleneck. For one serialized record type I've had to bite the bullet and implement a custom binary format because neither JSON nor GOB were fast enough.

--Jens

Xun Liu

unread,
Dec 25, 2013, 8:08:26 PM12/25/13
to golan...@googlegroups.com
Why this is marked as abuse? It has been marked as abuse.
Report not abuse

I'm in the process of converting some Python code into Go. Since Json encoding/decoding is one of the most common operations in the code so I did some simple json benchmarking for two packages. The benchmark is really simple: it decodes a json string 1000 times, and encodes it 1000 times. The results are:

1. simplejson is 5x faster than encoding/json in decoding.
2. simplejson is 2-3x faster than encoding/json in encoding. 


Python code:

jsonStr = '{"field_1": true, "field_2": true, "field_3": "XXXXYX", "field_4": true, "field_5": true, "field_6": true, "field_7": false, "field_8": true, "field_9": false, "field_10": false, "field_11": {"p": {}, "m": {}, "d": ["5", "3", "4", "8", "9", "7", "1", "2", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22"]}, "field_12": false, "field_13": false, "field_14": "LLLLLL", "field_15": true, "field_16": "en-US", "field_17": "2013-11-26T05:49:06.236458", "field_18": "Shengzhou", "field_19": true, "field_20": false, "field_21": false, "field_22": "xxxxx...@hotmail.com", "field_23": "http://www.xxxxxxx.com/yyyyyyyyy", "field_24": true, "field_25": true, "field_26": "0001-01-01T00:00:00", "field_27": true, "field_28": true, "field_29": false, "field_30": true, "field_31": "", "field_32": true, "field_33": true, "field_34": "wrqer@#$!WEF#@#DSDFFksdniwo3hOwR8ruCeNF.3IkeOe80Yko8n7HvpsrZm", "field_35": false, "field_36": true, "field_37": "0001-01-01T00:00:00", "field_38": "String values encode as JSON strings. InvalidUTF8Error will be returned if an invalid UTF-8 sequence is encountered", "field_39": "female", "field_40": true, "field_41": true, "field_42": "insadesmaenideni", "field_43": "xyxyxyxyx_1233305355583", "field_44": "US", "field_45": {}, "field_46": false, "field_47": 1353270713, "field_48": "2013-11-12T15:38:33.052768", "field_49": "2012-02-29T22:46:18", "field_50": true}'


NUM = 1000

def dec():

    for i in xrange(NUM):

        d = simplejson.loads(jsonStr)

 

t0 = time.time()

dec()

t1 = time.time()

taken_ms = (t1 - t0) * 1000

print "Loads Taken", taken_ms, taken_ms / NUM 


o = simplejson.loads(jsonStr)

def enc():

    for i in xrange(NUM):

        simplejson.dumps(o)


t0 = time.time()

enc()

t1 = time.time()

taken_ms = (t1 - t0) * 1000

print "Dumps Taken", taken_ms, taken_ms / NUM

Typical Output:

Loads Taken 17.8289413452 0.0178289413452

Dumps Taken 31.9888591766 0.0319888591766

Go code:

var JsonBytes = []byte(`{"field_1": true, "field_2": true, "field_3": "XXXXYX", "field_4": true, "field_5": true, "field_6": true, "field_7": false, "field_8": true, "field_9": false, "field_10": false, "field_11": {"p": {}, "m": {}, "d": ["5", "3", "4", "8", "9", "7", "1", "2", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22"]}, "field_12": false, "field_13": false, "field_14": "LLLLLL", "field_15": true, "field_16": "en-US", "field_17": "2013-11-26T05:49:06.236458", "field_18": "Shengzhou", "field_19": true, "field_20": false, "field_21": false, "field_22": "xxxxx...@hotmail.com", "field_23": "http://www.xxxxxxx.com/yyyyyyyyy", "field_24": true, "field_25": true, "field_26": "0001-01-01T00:00:00", "field_27": true, "field_28": true, "field_29": false, "field_30": true, "field_31": "", "field_32": true, "field_33": true, "field_34": "wrqer@#$!WEF#@#DSDFFksdniwo3hOwR8ruCeNF.3IkeOe80Yko8n7HvpsrZm", "field_35": false, "field_36": true, "field_37": "0001-01-01T00:00:00", "field_38": "String values encode as JSON strings. InvalidUTF8Error will be returned if an invalid UTF-8 sequence is encountered", "field_39": "female", "field_40": true, "field_41": true, "field_42": "insadesmaenideni", "field_43": "xyxyxyxyx_1233305355583", "field_44": "US", "field_45": {}, "field_46": false, "field_47": 1353270713, "field_48": "2013-11-12T15:38:33.052768", "field_49": "2012-02-29T22:46:18", "field_50": true}`)

var JsonObj map[string]interface{}

func init() {

    json.Unmarshal(JsonBytes, &JsonObj)

}

func BenchmarkJsonDecode(b *testing.B) {

    for i := 0; i < b.N; i++ {

        for j := 0; j < 1000; j++ {

            var r map[string]interface{}

            //var r struct{}

            json.Unmarshal(JsonBytes, &r) 

        }   

    }   

}

func BenchmarkJsonEncode(b *testing.B) {

    for i := 0; i < b.N; i++ {

        for j := 0; j < 1000; j++ {

            json.Marshal(JsonObj)

        }   

    }   

}

Output

BenchmarkJsonDecode       20   98819415 ns/op

BenchmarkJsonEncode       20   82070594 ns/op


simplejson takes 18ms to decode the json string for 1000 times while Go takes 99ms.
simplejson takes 32ms to encode the object and go takes 82ms.

If I change the following line in Go code 
var r map[string]interface{}
to
var r struct {}

It only helps the decoding performance by ~5%

BenchmarkJsonDecode       20   93115410 ns/op

The similar performance differences are observed using my production data. 

My go version:

go version go1.2 linux/amd64


Any pointers on how to improve Go's json performance are appreciated.

Thanks,

Xun


Reply all
Reply to author
Forward
0 new messages