Skip to main content
Lodum is designed for high performance by using runtime bytecode compilation (via Python AST) to generate specialized serialization and deserialization handlers for your classes.

Benchmark Results

The following benchmarks were run on Python 3.13.7 (win32). Results are in microseconds (μs) per operation (lower is better).

JSON Serialization (Object → JSON)

LibrarySimple (μs)Complex (μs)Nested (μs)
Lodum7.62 ± 1.8715.45 ± 2.0336.51 ± 3.67
Pydantic (v2)3.13 ± 1.633.31 ± 0.406.76 ± 0.52
Marshmallow12.73 ± 1.7330.23 ± 0.9773.29 ± 4.58
Native json (dict)4.29 ± 0.416.76 ± 0.578.78 ± 0.46
orjson (dict)0.50 ± 0.020.73 ± 0.020.98 ± 0.01

JSON Deserialization (JSON → Object)

LibrarySimple (μs)Complex (μs)Nested (μs)
Lodum21.75 ± 1.7042.52 ± 2.13131.67 ± 6.75
Pydantic (v2)3.21 ± 0.763.94 ± 0.7116.52 ± 0.95
Marshmallow31.21 ± 4.0172.18 ± 4.93226.99 ± 6.63
Native json (dict)3.15 ± 0.404.52 ± 0.647.59 ± 0.57
orjson (dict)0.77 ± 0.101.52 ± 0.062.84 ± 0.13

Binary Formats (Lodum)

FormatOperationSimple (μs)Complex (μs)Nested (μs)
MsgPackSerialization4.60 ± 1.3710.15 ± 0.4031.31 ± 3.03
Deserialization18.22 ± 2.1235.90 ± 2.62119.92 ± 7.01
CBORSerialization11.61 ± 0.8818.84 ± 0.7043.67 ± 2.76
Deserialization21.61 ± 2.0039.39 ± 3.38132.37 ± 4.49
PickleSerialization8.91 ± 0.7313.26 ± 0.9539.72 ± 2.00
Deserialization6.75 ± 0.429.87 ± 1.7516.21 ± 1.22

Performance Analysis

Lodum vs Marshmallow

Lodum consistently outperforms Marshmallow (often 2x faster), particularly in serialization and handling complex structures. This performance advantage comes from Lodum’s AST-based bytecode compilation approach.

Lodum vs Pydantic

Pydantic v2 remains faster due to its Rust-based core. However, Lodum provides a competitive pure-Python alternative with:
  • Zero binary dependencies
  • Full control over the compilation process
  • Excellent cross-platform compatibility (including WASM)

AST Optimization Benefits

The move to AST-based code generation has significantly improved performance compared to string-based exec methods while providing:
  • Better type safety
  • More informative error messages
  • Easier debugging of generated code

Thread Safety

The modular refactor introduced thread-safe global state management via Context without performance regressions, thanks to a lock-free fast path for handler cache lookups.

Optimization Tips

1. Reuse Compiled Handlers

Lodum compiles handlers once per class. The first serialization/deserialization call will be slower due to compilation, but subsequent calls use the cached handler:
from lodum import lodum, json

@lodum
class User:
    def __init__(self, id: int, name: str):
        self.id = id
        self.name = name

# First call: slower (includes compilation)
user1_json = json.dumps(User(1, "Alice"))

# Subsequent calls: fast (uses cached handler)
user2_json = json.dumps(User(2, "Bob"))
user3_json = json.dumps(User(3, "Charlie"))

2. Use Streaming for Large Datasets

For large files, use streaming to avoid loading everything into memory:
from lodum import lodum, json
from pathlib import Path

@lodum
class Record:
    def __init__(self, id: int, data: str):
        self.id = id
        self.data = data

# Stream large JSON arrays
for record in json.stream(Record, Path("large_file.json")):
    process(record)

3. Choose the Right Format

Based on the benchmarks:
  • MsgPack: Best all-around binary format (smallest size, good performance)
  • Pickle: Fastest deserialization, but Python-only and security concerns
  • CBOR: Good for IoT/embedded systems with standardization needs
  • JSON: Best for human-readable data and web APIs

4. Avoid Deep Nesting

Deeply nested structures have higher overhead. Consider flattening your data structures when possible:
# Less efficient
@lodum
class DeeplyNested:
    def __init__(self, level1: "Level1"):
        self.level1 = level1

# More efficient
@lodum
class Flattened:
    def __init__(self, data: dict[str, int]):
        self.data = data

5. Use Binary Formats for Internal Services

If you control both ends of the communication:
from lodum import msgpack

# 2-3x faster than JSON for complex objects
data = msgpack.dumps(my_object)
restored = msgpack.loads(MyClass, data)

Running Benchmarks Yourself

To run benchmarks on your own machine:
cd benchmarks/
pip install -r requirements.txt
python run_benchmarks.py
This will generate a detailed report comparing Lodum against other serialization libraries on your specific hardware and Python version.

Memory Usage

Lodum’s AST compilation approach has minimal memory overhead:
  • Handler Cache: One compiled function per @lodum class
  • Context: Thread-local state with lock-free fast path
  • Streaming: O(1) memory for large files when using stream() functions

Future Optimizations

Planned performance improvements:
  1. Cython Acceleration: Optional Cython-compiled core for 5-10x speedup
  2. Parallel Serialization: Multi-threaded serialization for large collections
  3. Zero-Copy Deserialization: Direct memory mapping for binary formats
  4. JIT Optimization: Integration with PyPy’s JIT compiler

Build docs developers (and LLMs) love