Skip to content

Instantly share code, notes, and snippets.

@dropwhile
Last active February 28, 2020 05:43
Show Gist options
  • Save dropwhile/4073643 to your computer and use it in GitHub Desktop.
Save dropwhile/4073643 to your computer and use it in GitHub Desktop.
python serialization speed comparison
virtualenv --no-site-packages hodor
hodor/bin/pip install simplejson ujson cbor tnetstring msgpack-python
curl -s 'http://www.json-generator.com/api/json/get/cvfsLVmKiG?indent=2' > test.json
hodor/bin/python shootout.py
## python 2.7.7 on centos 6.6
..::DUMPS::..
json: 3.068149 100.00% 90460 100.00%
simplejson: 5.616200 183.05% 90460 100.00%
ujson: 1.875687 61.13% 89261 98.67%
tnetstring: 1.162987 37.91% 90207 99.72%
msgpack: 1.110323 36.19% 86798 95.95%
cbor: 0.678674 22.12% 86778 95.93%
marshal: 1.896508 61.81% 91600 101.26%
pickle: 42.890038 1397.91% 91162 100.78%
pickle2: 47.861820 1559.96% 87499 96.73%
cPickle: 7.550282 246.09% 91452 101.10%
cPickle2: 1.689119 55.05% 85602 94.63%
..::LOADS::..
serializer time time-diff
json: 7.419880 100.00%
simplejson: 2.558231 34.48%
ujson: 2.890960 38.96%
tnetstring: 1.000095 13.48%
msgpack: 0.858918 11.58%
cbor: 0.947492 12.77%
marshal: 0.975319 13.14%
pickle: 35.305399 475.82%
pickle2: 20.916351 281.90%
cPickle: 4.277538 57.65%
cPickle2: 1.347456 18.16%
## [PyPy 2.4.0 with GCC 4.8.2] on centos 6.6
## note: tests probably don't run long enough to get much JIT benefit
..::DUMPS::..
serializer time time-diff size size-diff
json: 4.242018 100.00% 90460 100.00%
simplejson: 17.838388 420.52% 90460 100.00%
ujson: tests failed: 'ujson'
tnetstring: 6.875353 162.08% 90207 99.72%
msgpack: 3.891492 91.74% 86798 95.95%
cbor: 4.522691 106.62% 86778 95.93%
marshal: 5.291648 124.74% 91600 101.26%
pickle: 22.375729 527.48% 95288 105.34%
pickle2: 9.940469 234.33% 89020 98.41%
cPickle: 25.145335 592.77% 95291 105.34%
cPickle2: 10.484767 247.16% 89023 98.41%
..::LOADS::..
serializer time time-diff
json: 3.343928 100.00%
simplejson: 15.526334 464.31%
ujson: tests failed: 'ujson'
tnetstring: 67.718456 2025.12%
msgpack: 1.826920 54.63%
cbor: 6.167334 184.43%
marshal: 4.911089 146.87%
pickle: 9.324833 278.86%
pickle2: 7.627817 228.11%
cPickle: 8.596466 257.08%
cPickle2: 7.294959 218.16%
import sys
import random
import json
import simplejson
try:
import ujson
except ImportError:
pass
import tnetstring
import marshal
import pickle
import cPickle
import cbor
import msgpack
import functools
from tnetstring.tests.test_format import FORMAT_EXAMPLES, get_random_object
class P(object):
pass
pickle2 = P()
pickle2.dumps = functools.partial(pickle.dumps, protocol=2)
pickle2.loads = pickle.loads
sys.modules['pickle2'] = pickle2
cPickle2 = P()
cPickle2.dumps = functools.partial(cPickle.dumps, protocol=2)
cPickle2.loads = cPickle.loads
sys.modules['cPickle2'] = cPickle2
try:
import __pypy__
tnetstrng = tnetstring
tnetstring = P()
tnetstring.dumps = functools.partial(tnetstrng.dumps, encoding="utf8")
tnetstring.loads = functools.partial(tnetstrng.loads, encoding="utf8")
sys.modules['tnetstring'] = tnetstring
except:
pass
# test.json generated from http://www.json-generator.com/
# http://www.json-generator.com/api/json/get/cvfsLVmKiG?indent=2
testdict = simplejson.load(open('test.json','rb'))
def thrasher(serializer):
m = sys.modules[serializer]
dumper = getattr(m, 'dumps')
loader = getattr(m, 'loads')
def thrash():
assert loader(dumper(testdict)) == testdict
return thrash
def thrash_loads(serializer):
m = sys.modules[serializer]
dumper = getattr(m, 'dumps')
loader = getattr(m, 'loads')
data = dumper(testdict)
def thrash():
loader(data)
return thrash
def thrash_dumps(serializer):
m = sys.modules[serializer]
dumper = getattr(m, 'dumps')
def thrash():
dumper(testdict)
return thrash
PERMUTATIONS=10000
def print_round(name, tx, to, l=0, jl=0):
if l or jl:
print "%12s:\t%f\t%7.2f%%\t%d\t%7.2f%%" % (
name, tx,
round((tx / to) * 100,2),
l,
round((l / jl) * 100,2))
else:
print "%12s:\t%f\t%7.2f%%" % (
name, tx,
round((tx / to) * 100,2))
if __name__ == "__main__":
import timeit
tmodules = ("simplejson", "ujson", "tnetstring", "msgpack", "cbor",
"marshal", "pickle", "pickle2", "cPickle", "cPickle2")
if len(sys.argv) > 1:
tmodules = sys.argv[1].split(',')
print "..::DUMPS::.."
print "%12s\t%s\t\t%s\t%s\t%s" % ("serializer","time","time-diff","size", "size-diff")
to = timeit.Timer(
"dumps()",
"from shootout import thrash_dumps;dumps=thrash_dumps('json')")
to =to.timeit(number=PERMUTATIONS)
jlen = float(len(json.dumps(testdict)))
print_round("json", to, to, jlen, jlen)
for x in tmodules:
try:
tx = timeit.Timer(
"dumps()",
"from shootout import thrash_dumps;dumps=thrash_dumps('%s')" % x)
tx = tx.timeit(number=PERMUTATIONS)
m = sys.modules[x]
print_round(x, tx, to, len(m.dumps(testdict)), jlen)
except Exception as e:
print "%12s: tests failed: %s" % (x, e)
print ""
print "..::LOADS::.."
print "%12s\t%s\t\t%s" % ("serializer","time","time-diff")
to = timeit.Timer(
"loads()",
"from shootout import thrash_loads;loads=thrash_loads('json')")
to =to.timeit(number=PERMUTATIONS)
print_round("json", to, to)
for x in tmodules:
try:
tx = timeit.Timer(
"loads()",
"from shootout import thrash_loads;loads=thrash_loads('%s')" % x)
tx = tx.timeit(number=PERMUTATIONS)
m = sys.modules[x]
print_round(x, tx, to)
except Exception as e:
print "%12s: tests failed: %s" % (x, e)
@pryg-skok
Copy link

Thanks for tests!

@TerminalWitchcraft
Copy link

Thank you for the comparisons

@ifduyue
Copy link

ifduyue commented Jan 6, 2017

Here is the result benchmarked on my Macbook Pro with Python 2.7.13

1355e6dc-1dce-4604-abda-4e78ba7cabd2

bef199f2-bc78-4cf2-b045-a777e13900e9

@halilozercan
Copy link

halilozercan commented Sep 3, 2017

Tested on my Acer Chromebook 14 with Ubuntu 16.04 Crouton, Python 2.7.13

screenshot_2017-09-03_20-37-24

My objects contain really large long values. That is why ujson and msgpack fails. I think it is also important to have that detail.

@spacemanspiff2007
Copy link

Python 3.6 on Win7:
Pickle performs really well there.

..::DUMPS::..
  serializer    time            time-diff       size    size-diff
        json:   5.227366         100.00%        90460    100.00%
  simplejson:   6.327719         121.05%        90460    100.00%
     msgpack:   2.010781          38.47%        86798     95.95%
     marshal:   0.669897          12.82%        86909     96.07%
      pickle:   0.984644          18.84%        89020     98.41%
     pickle2:   0.964434          18.45%        89020     98.41%
     pickle4:   0.918402          17.57%        85625     94.66%

..::LOADS::..
  serializer    time            time-diff
        json:   3.465400         100.00%
  simplejson:   3.461371          99.88%
     msgpack:   0.914066          26.38%
     marshal:   0.827754          23.89%
      pickle:   1.156223          33.36%
     pickle2:   1.111155          32.06%
     pickle4:   1.088305          31.40%

@bmunoz89
Copy link

bmunoz89 commented Oct 1, 2018

Python 3.6.6 on Mac:

..::DUMPS::..
  serializer	time		time-diff	size	size-diff
        json:	4.442723	 100.00%	90460	 100.00%
  simplejson:	4.867349	 109.56%	90460	 100.00%
       ujson:	2.020214	  45.47%	89261	  98.67%
     msgpack:	0.740636	  16.67%	86798	  95.95%
     marshal:	0.623901	  14.04%	86909	  96.07%
        cbor:	1.372539	  30.89%	86778	  95.93%
      pickle:	0.989589	  22.27%	89020	  98.41%

..::LOADS::..
  serializer	time		time-diff
        json:	3.099072	 100.00%
  simplejson:	2.870310	  92.62%
       ujson:	3.670731	 118.45%
     msgpack:	1.002717	  32.36%
     marshal:	1.046321	  33.76%
        cbor:	1.803092	  58.18%
      pickle:	1.298057	  41.89%

@crhan
Copy link

crhan commented Oct 9, 2018

python3 compatible code is here: https://gist.github.com/crhan/f04ddb7373533bae4d051271497e080e

python 3.6.6 on Mac:

difference:

  1. use a json data length is: 4978960
  2. PERMUTATIONS = 100

image

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment