1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
|
#!/usr/bin/env python3
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import dataclasses
import io
import json
import os
from timeit import timeit
from tabulate import tabulate
import orjson
os.sched_setaffinity(os.getpid(), {0, 1})
@dataclasses.dataclass
class Member:
id: int
active: bool
@dataclasses.dataclass
class Object:
id: int
name: str
members: list[Member]
objects_as_dataclass = [
Object(i, str(i) * 3, [Member(j, True) for j in range(10)])
for i in range(100000, 102000)
]
objects_as_dict = [dataclasses.asdict(each) for each in objects_as_dataclass]
output_in_kib = len(orjson.dumps(objects_as_dict)) / 1024
print(f"{output_in_kib:,.0f}KiB output (orjson)")
def default(__obj):
if dataclasses.is_dataclass(__obj):
return dataclasses.asdict(__obj)
headers = ("Library", "dict (ms)", "dataclass (ms)", "vs. orjson")
LIBRARIES = ("orjson", "json")
ITERATIONS = 100
def per_iter_latency(val):
if val is None:
return None
return (val * 1000) / ITERATIONS
table = []
for lib_name in LIBRARIES:
if lib_name == "json":
as_dict = timeit(
lambda: json.dumps(objects_as_dict).encode("utf-8"),
number=ITERATIONS,
)
as_dataclass = timeit(
lambda: json.dumps(objects_as_dataclass, default=default).encode("utf-8"),
number=ITERATIONS,
)
elif lib_name == "orjson":
as_dict = timeit(lambda: orjson.dumps(objects_as_dict), number=ITERATIONS)
as_dataclass = timeit(
lambda: orjson.dumps(
objects_as_dataclass,
None,
orjson.OPT_SERIALIZE_DATACLASS,
),
number=ITERATIONS,
)
orjson_as_dataclass = per_iter_latency(as_dataclass)
else:
raise NotImplementedError
as_dict = per_iter_latency(as_dict)
as_dataclass = per_iter_latency(as_dataclass)
if lib_name == "orjson":
compared_to_orjson = 1
elif as_dataclass:
compared_to_orjson = int(as_dataclass / orjson_as_dataclass)
else:
compared_to_orjson = None
table.append(
(
lib_name,
f"{as_dict:,.2f}" if as_dict else "",
f"{as_dataclass:,.2f}" if as_dataclass else "",
f"{compared_to_orjson:d}" if compared_to_orjson else "",
),
)
buf = io.StringIO()
buf.write(tabulate(table, headers, tablefmt="github"))
buf.write("\n")
print(buf.getvalue())
|