| Markdown → HTML Benchmark | |||
| 4,450-byte document, 1,000 iterations, best-of-average | |||
| Package | Engine | Time (µs) | Relative |
|---|---|---|---|
| multimark | cmark-gfm (C) | 98.6 | 1.0× |
| cmarkgfm | cmark-gfm (C) | 114.3 | 1.2× |
| mistune | Pure Python | 1,773.0 | 18.0× |
| commonmark.py | Pure Python | 3,016.9 | 30.6× |
| markdown-it-py | Pure Python | 3,031.3 | 30.7× |
| Lower is better. 'Relative' is normalized to multimark = 1.0×. | |||
Performance
This page benchmarks multimark against other popular Python Markdown parsers and explains why multimark is fast.
Benchmark: Markdown to HTML
We render a ~4 KB Markdown document (with headings, lists, code blocks, inline formatting, and a table) 1,000 times and measure the average time per call. All parsers produce HTML output. The benchmark document is repeated 10 times to reach a realistic size, and each library is configured with GFM table and strikethrough support where available.
Why multimark Is Fast
multimark wraps a compiled C library via CFFI. The actual parsing and rendering happens entirely in C, with Python involved only for the function call overhead and string encoding/decoding. This architecture gives you the ergonomics of Python with the speed of native code.
For typical Markdown documents (a few kilobytes), rendering completes in microseconds. The overhead of the Python-to-C boundary is negligible compared to what a pure-Python parser would spend on the same input.
Memory Efficiency
Each render call allocates memory for the AST and output buffer in C, then frees it before returning. There is no persistent state between calls, which means memory usage stays constant regardless of how many documents you process.
import sys
from multimark import markdown_to_html
result = markdown_to_html("# Hello\n\nWorld\n")
print(f"Result type: {type(result).__name__}")
print(f"Result size: {sys.getsizeof(result)} bytes")Result type: str
Result size: 69 bytes
The C library manages its own memory internally. Python only holds the final output string, so you do not need to worry about manual memory management or cleanup.
Tips for Maximum Throughput
Performance tips
Minimize extension overhead. Each enabled extension adds a small amount of parsing work. If you do not need tables or autolinks for a particular batch, omit them.
Reuse option values. Building the options bitmask is cheap, but defining it once outside a loop avoids redundant work.
Process in batches, not one-at-a-time. If you are reading files from disk, batch the I/O and render calls together rather than interleaving with other heavy operations.
Avoid unnecessary encoding. multimark accepts str and handles UTF-8 encoding internally. Do not pre-encode to bytes and decode back; just pass the string directly.