-
-
Save CTimmerman/1f328f02ac2740f4c90d to your computer and use it in GitHub Desktop.
Python serialization benchmark
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| Python serialization benchmark | |
| Based on https://gist.github.com/marians/f1314446b8bf4d34e782 | |
| 2014-11-11 v1.0 | |
| 2014-11-12 v1.1 Added compression and output size. | |
| 2026-02-12 v2.0 Added Fory and CBOR. Removed compression. | |
| """ | |
| import json, marshal, pickle, random | |
| from dataclasses import dataclass | |
| from hashlib import md5 | |
| from time import time | |
| from typing import List, Dict | |
| import uuid | |
| #from zlib import compress, decompress # halves json float size (19 kB to 10 kB) | |
| import cbor2, msgpack, pyfory, thrift | |
| #import ujson # from http://www.lfd.uci.edu/~gohlke/pythonlibs/#ujson | |
| # 2 to 3 times slower and up to 50% larger output than marshal. | |
| # "pyfory provides a Python-native serialization mode that offers the same functionality as pickle/cloudpickle, but with significantly better performance, smaller data size, and enhanced security features." - https://fory.apache.org/docs/guide/python/native_mode | |
| fory = pyfory.Fory(xlang=False, ref=False, strict=False) | |
| @dataclass | |
| class Person: | |
| name: str | |
| age: int | |
| scores: List[int] | |
| metadata: Dict[str, str] | |
| data_size = 10 | |
| test_runs = 100_000 | |
| if __name__ == "__main__": | |
| payload = { | |
| "int": [random.randrange(0, 9999) for i in range(data_size)], | |
| "float": [(random.randrange(0, 99) + random.random()) for i in range(data_size)], | |
| "str": [md5(str(random.random()).encode('utf8')).hexdigest() for i in range(data_size)], | |
| "dict": [dict((f"Key {i}", str(uuid.uuid4())) for i in range(data_size))], | |
| "bytes": [[bytes([random.randint(0, 255) for j in range(200)]) for i in range(data_size)]], | |
| "class": [Person(str(uuid.uuid4()), random.randint(0, 100), [random.randint(-100, 100) for j in range(10)], {"generic {i}": str(uuid.uuid4())}) for i in range(data_size)], | |
| } | |
| modules = [marshal, msgpack, pyfory, pickle, cbor2, json] | |
| print(f"{test_runs:,d} times {data_size:,d} elements:") | |
| for module in modules: | |
| name = module.__name__ | |
| cumulative = time() | |
| for payload_type in payload: | |
| data = payload[payload_type] | |
| if name == "pyfory": | |
| dumps = fory.dumps | |
| loads = fory.loads | |
| elif name == "thrift": | |
| dumps = thrift.save | |
| loads = thrift.load | |
| else: | |
| dumps = module.dumps | |
| loads = module.loads | |
| start = time() | |
| try: | |
| if name in ['pickle', 'cPickle']: | |
| for i in range(test_runs): serialized = dumps(data, protocol=-1) # -1 = highest available (2 in Python 2; 3 in Python 3.4 (2x speed)) | |
| else: | |
| for i in range(test_runs): serialized = dumps(data) | |
| w = time() - start | |
| start = time() | |
| for i in range(test_runs): unserialized = loads(serialized) | |
| r = time() - start | |
| except (TypeError, ValueError) as ex: | |
| print(f"{module.__name__}\t{payload_type}\t{ex}") | |
| continue | |
| print(f"{module.__name__}\t{payload_type}\t{w:6.3f} sW {r:6.3f} sR {w+r:6.3f} sT {time() - cumulative:6.3f} sC {len(serialized):10,d} B") | |
| print() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 32-bit results in 64-bit Windows 7 Enterprise on Xeon W3540 @ 2.93 GHz 2.93 GHz (Dell Precision T3500): | |
| C:\Python27\python.exe -u "serialization_benchmark.py" | |
| 1000 times 1000 elements: | |
| json int W 0.125 R 0.156 | |
| pickle int W 2.808 R 1.139 | |
| cPickle int W 0.047 R 0.046 | |
| marshal int W 0.016 R 0.031 | |
| json float W 1.981 R 0.624 | |
| pickle float W 2.607 R 1.092 | |
| cPickle float W 0.063 R 0.062 | |
| marshal float W 0.047 R 0.031 | |
| json str W 0.172 R 0.437 | |
| pickle str W 5.149 R 2.309 | |
| cPickle str W 0.281 R 0.156 | |
| marshal str W 0.109 R 0.047 | |
| C:\pypy-1.6\pypy-c -u "serialization_benchmark.py" | |
| 1000 times 1000 elements: | |
| json int W 0.515 R 0.452 | |
| pickle int W 0.546 R 0.219 | |
| cPickle int W 0.577 R 0.171 | |
| marshal int W 0.032 R 0.031 | |
| json float W 2.390 R 1.341 | |
| pickle float W 0.656 R 0.436 | |
| cPickle float W 0.593 R 0.406 | |
| marshal float W 0.327 R 0.203 | |
| json str W 1.141 R 1.186 | |
| pickle str W 0.702 R 0.546 | |
| cPickle str W 0.828 R 0.562 | |
| marshal str W 0.265 R 0.078 | |
| c:\Python34\python -u "serialization_benchmark.py" | |
| 1000 times 1000 elements: | |
| json int W 0.203 R 0.140 6 kB | |
| pickle int W 0.047 R 0.062 3 kB | |
| pickle int W 0.031 R 0.062 3 kB | |
| marshal int W 0.031 R 0.047 5 kB | |
| json float W 1.935 R 0.749 19 kB | |
| pickle float W 0.047 R 0.062 9 kB | |
| pickle float W 0.047 R 0.062 9 kB | |
| marshal float W 0.047 R 0.047 9 kB | |
| json str W 0.281 R 0.187 36 kB | |
| pickle str W 0.125 R 0.140 35 kB | |
| pickle str W 0.125 R 0.140 35 kB | |
| marshal str W 0.094 R 0.078 34 kB | |
| v1.1 zlib: | |
| c:\Python34\python -u "serialization_benchmark.py" | |
| 1000 times 1000 elements: | |
| json int 0.686 sW 0.187 sR 3 kB | |
| pickle int 0.187 sW 0.078 sR 2 kB | |
| pickle int 0.187 sW 0.094 sR 2 kB | |
| marshal int 0.702 sW 0.094 sR 3 kB | |
| json float 3.325 sW 0.874 sR 10 kB | |
| pickle float 0.546 sW 0.140 sR 8 kB | |
| pickle float 0.546 sW 0.125 sR 8 kB | |
| marshal float 0.468 sW 0.109 sR 8 kB | |
| json str 2.590 sW 0.608 sR 20 kB | |
| pickle str 2.496 sW 0.452 sR 20 kB | |
| pickle str 2.418 sW 0.421 sR 20 kB | |
| marshal str 1.981 sW 0.374 sR 20 kB | |
| v1.1 bz2: | |
| c:\Python34\python -u "serialization_benchmark.py" | |
| 1000 times 1000 elements: | |
| json int 1.188 sW 0.446 sR 2 kB | |
| pickle int 1.263 sW 0.317 sR 2 kB | |
| pickle int 1.295 sW 0.271 sR 2 kB | |
| marshal int 1.627 sW 0.270 sR 2 kB | |
| json float 4.828 sW 1.706 sR 8 kB | |
| pickle float 2.737 sW 0.749 sR 8 kB | |
| pickle float 2.699 sW 0.718 sR 8 kB | |
| marshal float 2.590 sW 0.733 sR 8 kB | |
| json str 5.179 sW 1.778 sR 17 kB | |
| pickle str 4.883 sW 1.888 sR 17 kB | |
| pickle str 4.849 sW 1.857 sR 17 kB | |
| marshal str 4.782 sW 1.741 sR 17 kB | |
| c:\Python34\python -u "serialization_benchmark_nocompress.py" | |
| 10 times 100000 elements: | |
| json int 0.187 sW 0.140 sR 589 kB | |
| pickle int 0.031 sW 0.062 sR 298 kB | |
| pickle int 0.031 sW 0.047 sR 298 kB | |
| marshal int 0.047 sW 0.047 sR 500 kB | |
| json float 1.778 sW 0.686 sR 1919 kB | |
| pickle float 0.062 sW 0.047 sR 900 kB | |
| pickle float 0.047 sW 0.062 sR 900 kB | |
| marshal float 0.047 sW 0.031 sR 900 kB | |
| json str 0.312 sW 0.203 sR 3600 kB | |
| pickle str 0.250 sW 0.156 sR 3501 kB | |
| pickle str 0.250 sW 0.156 sR 3501 kB | |
| marshal str 0.125 sW 0.094 sR 3400 kB | |
| 2.7 zlib: | |
| C:\Python27\python.exe -u "serialization_benchmark.py" | |
| 10 times 100000 elements: | |
| json int 1.108 sW 0.814 sR 226 kB | |
| pickle int 3.011 sW 1.186 sR 216 kB | |
| cPickle int 0.265 sW 0.094 sR 216 kB | |
| marshal int 1.154 sW 0.078 sR 239 kB | |
| json float 4.509 sW 1.030 sR 906 kB | |
| pickle float 4.025 sW 1.185 sR 797 kB | |
| cPickle float 1.498 sW 0.156 sR 797 kB | |
| marshal float 1.108 sW 0.125 sR 793 kB | |
| json str 3.276 sW 0.780 sR 1982 kB | |
| pickle str 9.034 sW 2.981 sR 2259 kB | |
| cPickle str 4.135 sW 0.686 sR 2259 kB | |
| marshal str 2.980 sW 0.421 sR 1989 kB | |
| zlib: | |
| c:\Python34\python -u "serialization_benchmark.py" | |
| 10 times 100000 elements: | |
| json int 1.123 sW 0.218 sR 226 kB | |
| pickle int 0.265 sW 0.094 sR 216 kB | |
| pickle int 0.281 sW 0.078 sR 216 kB | |
| marshal int 1.170 sW 0.078 sR 242 kB | |
| json float 4.227 sW 0.842 sR 906 kB | |
| pickle float 1.529 sW 0.125 sR 797 kB | |
| pickle float 1.529 sW 0.125 sR 797 kB | |
| marshal float 1.154 sW 0.109 sR 794 kB | |
| json str 3.182 sW 0.468 sR 1983 kB | |
| pickle str 3.026 sW 0.452 sR 1966 kB | |
| pickle str 3.074 sW 0.437 sR 1966 kB | |
| marshal str 2.637 sW 0.343 sR 1933 kB | |
| bz2: | |
| c:\Python34\python -u "serialization_benchmark.py" | |
| 10 times 100000 elements: | |
| json int 1.061 sW 0.655 sR 177 kB | |
| pickle int 0.499 sW 0.218 sR 171 kB | |
| pickle int 0.499 sW 0.234 sR 171 kB | |
| marshal int 0.608 sW 0.374 sR 169 kB | |
| json float 4.415 sW 2.683 sR 769 kB | |
| pickle float 1.981 sW 1.170 sR 758 kB | |
| pickle float 1.622 sW 0.920 sR 758 kB | |
| marshal float 1.982 sW 1.185 sR 770 kB | |
| json str 5.647 sW 3.931 sR 1711 kB | |
| pickle str 5.381 sW 3.759 sR 1712 kB | |
| pickle str 5.335 sW 3.806 sR 1712 kB | |
| marshal str 5.179 sW 3.650 sR 1711 kB | |
| Python 3.13.12 (tags/v3.13.12:1cbe481, Feb 3 2026, 18:22:25) [MSC v.1944 64 bit (AMD64)] on win32 | |
| python bench_serializers.py | |
| 100,000 times 10 elements: | |
| marshal int 0.056 sW 0.040 sR 0.096 sT 0.096 sC 55 B | |
| marshal float 0.059 sW 0.037 sR 0.096 sT 0.192 sC 95 B | |
| marshal str 0.053 sW 0.051 sR 0.104 sT 0.297 sC 345 B | |
| marshal dict 0.075 sW 0.136 sR 0.212 sT 0.509 sC 457 B | |
| marshal bytes 0.079 sW 0.056 sR 0.135 sT 0.644 sC 2,060 B | |
| marshal class unmarshallable object | |
| msgpack int 0.110 sW 0.047 sR 0.158 sT 0.158 sC 31 B | |
| msgpack float 0.094 sW 0.044 sR 0.138 sT 0.296 sC 91 B | |
| msgpack str 0.098 sW 0.058 sR 0.155 sT 0.451 sC 341 B | |
| msgpack dict 0.152 sW 0.170 sR 0.322 sT 0.774 sC 442 B | |
| msgpack bytes 0.129 sW 0.062 sR 0.191 sT 0.966 sC 2,022 B | |
| msgpack class can not serialize 'Person' object | |
| pyfory int 0.082 sW 0.110 sR 0.192 sT 0.192 sC 26 B | |
| pyfory float 0.068 sW 0.101 sR 0.169 sT 0.361 sC 86 B | |
| pyfory str 0.088 sW 0.130 sR 0.218 sT 0.579 sC 346 B | |
| pyfory dict 0.131 sW 0.250 sR 0.381 sT 0.960 sC 451 B | |
| pyfory bytes 0.662 sW 0.346 sR 1.008 sT 1.968 sC 2,029 B | |
| pyfory class 1.197 sW 1.737 sR 2.934 sT 4.902 sC 1,219 B | |
| pickle int 0.115 sW 0.066 sR 0.180 sT 0.180 sC 46 B | |
| pickle float 0.109 sW 0.070 sR 0.179 sT 0.359 sC 106 B | |
| pickle str 0.136 sW 0.089 sR 0.225 sT 0.584 sC 366 B | |
| pickle dict 0.212 sW 0.180 sR 0.391 sT 0.976 sC 489 B | |
| pickle bytes 0.148 sW 0.093 sR 0.241 sT 1.217 sC 2,049 B | |
| pickle class 1.366 sW 1.253 sR 2.619 sT 3.836 sC 1,490 B | |
| cbor2 int 0.503 sW 0.139 sR 0.642 sT 0.642 sC 31 B | |
| cbor2 float 0.542 sW 0.138 sR 0.679 sT 1.322 sC 91 B | |
| cbor2 str 0.567 sW 0.170 sR 0.737 sT 2.059 sC 341 B | |
| cbor2 dict 0.719 sW 0.311 sR 1.030 sT 3.089 sC 442 B | |
| cbor2 bytes 0.686 sW 0.170 sR 0.856 sT 3.945 sC 2,022 B | |
| cbor2 class cannot serialize type <class '__main__.Person'> | |
| json int 0.234 sW 0.196 sR 0.430 sT 0.430 sC 60 B | |
| json float 0.702 sW 0.429 sR 1.131 sT 1.562 sC 193 B | |
| json str 0.314 sW 0.203 sR 0.517 sT 2.080 sC 360 B | |
| json dict 0.429 sW 0.321 sR 0.750 sT 2.830 sC 492 B | |
| json bytes Object of type bytes is not JSON serializable | |
| json class Object of type Person is not JSON serializable | |
| 10 times 100,000 elements: | |
| marshal int 0.019 sW 0.028 sR 0.047 sT 0.047 sC 500,005 B | |
| marshal float 0.026 sW 0.025 sR 0.050 sT 0.098 sC 900,005 B | |
| marshal str 0.034 sW 0.040 sR 0.074 sT 0.173 sC 3,400,005 B | |
| marshal dict 0.065 sW 0.209 sR 0.274 sT 0.447 sC 4,888,897 B | |
| marshal bytes 0.192 sW 0.068 sR 0.260 sT 0.707 sC 20,500,010 B | |
| marshal class unmarshallable object | |
| msgpack int 0.040 sW 0.028 sR 0.068 sT 0.068 sC 296,082 B | |
| msgpack float 0.030 sW 0.029 sR 0.059 sT 0.126 sC 900,005 B | |
| msgpack str 0.063 sW 0.039 sR 0.103 sT 0.229 sC 3,400,005 B | |
| msgpack dict 0.127 sW 0.279 sR 0.406 sT 0.636 sC 4,788,896 B | |
| msgpack bytes 0.198 sW 0.077 sR 0.275 sT 0.911 sC 20,200,006 B | |
| msgpack class can not serialize 'Person' object | |
| pyfory int 0.019 sW 0.039 sR 0.058 sT 0.058 sC 217,419 B | |
| pyfory float 0.008 sW 0.034 sR 0.042 sT 0.100 sC 800,008 B | |
| pyfory str 0.043 sW 0.061 sR 0.105 sT 0.204 sC 3,400,008 B | |
| pyfory dict 0.067 sW 0.209 sR 0.276 sT 0.480 sC 4,790,471 B | |
| pyfory bytes 0.640 sW 0.245 sR 0.885 sT 1.366 sC 20,200,011 B | |
| pyfory class 1.171 sW 3.560 sR 4.730 sT 6.096 sC 12,000,542 B | |
| pickle int 0.020 sW 0.074 sR 0.093 sT 0.093 sC 297,680 B | |
| pickle float 0.033 sW 0.041 sR 0.074 sT 0.168 sC 900,331 B | |
| pickle str 0.173 sW 0.066 sR 0.239 sT 0.407 sC 3,500,691 B | |
| pickle dict 0.315 sW 0.257 sR 0.572 sT 0.979 sC 5,089,802 B | |
| pickle bytes 0.279 sW 0.097 sR 0.376 sT 1.355 sC 20,302,998 B | |
| pickle class 2.157 sW 2.296 sR 4.453 sT 5.808 sC 14,194,787 B | |
| cbor2 int 0.071 sW 0.095 sR 0.166 sT 0.166 sC 297,163 B | |
| cbor2 float 0.099 sW 0.049 sR 0.148 sT 0.314 sC 900,005 B | |
| cbor2 str 0.168 sW 0.085 sR 0.253 sT 0.567 sC 3,400,005 B | |
| cbor2 dict 0.349 sW 0.264 sR 0.613 sT 1.180 sC 4,788,896 B | |
| cbor2 bytes 0.618 sW 0.161 sR 0.780 sT 1.960 sC 20,200,006 B | |
| cbor2 class cannot serialize type <class '__main__.Person'> | |
| json int 0.084 sW 0.092 sR 0.176 sT 0.176 sC 588,801 B | |
| json float 0.627 sW 0.370 sR 0.997 sT 1.173 sC 1,918,211 B | |
| json str 0.187 sW 0.092 sR 0.278 sT 1.452 sC 3,600,000 B | |
| json dict 0.283 sW 0.353 sR 0.636 sT 2.087 sC 5,288,892 B | |
| json bytes Object of type bytes is not JSON serializable | |
| json class Object of type Person is not JSON serializable |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It appears that Microsoft GitHub's Gist search excludes this entry for some season. Maybe this comment with the words "benchmark", "pickle", and "marshal" will help find it in the future.