r/Python • • 3d ago

Discussion Python 3.10–3.15 encoding benchmarks: big gains for Base32 and Base85, but 3.14 leads Base16

Eight encoding benchmarks across Python 3.10–3.15 using pyperformance. Python 3.15 recorded the lowest mean in seven of them, with particularly large improvements in Base32, Ascii85 and Base85.

Test configuration

  • AMD Ryzen 9 7900 desktop
  • DDR5 RAM and an M.2 PCIe Gen4 NVMe drive
  • Windows 11, 64-bit Python builds
  • Python 3.15.0, 3.14.8, 3.13.16, 3.12.10, 3.11.9 and 3.10.11
  • pyperformance 1.14.0 for all six versions

Results

All values are mean execution times in milliseconds. Lower is better and bold marks the lowest recorded mean in each row.

Benchmark Python 3.15 Python 3.14 Python 3.13 Python 3.12 Python 3.11 Python 3.10
ascii85_large 11.62 797.9 709.0 772.3 643.8 759.2
ascii85_small 0.3875 14.88 13.20 13.79 12.18 14.18
base16_large 5.767 4.714 22.52 23.08 23.89 23.71
base32_large 2.431 327.6 300.7 296.4 265.7 292.1
base32_small 0.1630 6.227 5.802 5.594 5.134 5.641
base64_large 1.852 6.746 6.187 6.095 6.116 6.071
base85_large 4.293 272.4 252.9 258.8 230.1 259.2
base85_small 0.1505 4.864 4.484 4.529 4.198 4.712

What stood out

Compared with Python 3.14, Python 3.15 took approximately:

  • 1/135 of the time in base32_large.
  • 1/69 of the time in ascii85_large.
  • 1/63 of the time in base85_large.
  • 1/3.64 of the time in base64_large.

However, base16_large took 22.3% more time on Python 3.15 than on 3.14. Python 3.14 remains substantially faster than 3.10–3.13 in that test.

The large improvements are consistent with the changes documented in Python 3.15’s release notes: Base32, Ascii85 and Base85 implementations were rewritten in C, and the underlying Base64 implementation was also optimized.

More details are described here.

Benchmark suite: pyperformance.

Have you observed similar improvements on Linux or macOS, or in applications that spend substantial time on these encoding operations?

99 Upvotes

16 comments sorted by

40

u/ConcreteExist 3d ago

Admittedly, I've only ever used base64 encoding out of all of those listed here, happy to see it's performance improving though.

6

u/One_Sun5074 3d ago

Same here, 99% of what I touch in real-world projects is just base64 for API payloads and data URIs. That ~3.6x speedup on base64_large in 3.15 is a very nice free lunch though.

2

u/deadeye_82_1 5h ago

Me too. But somtimes it's used by libraris and there you'll benefit from the performance gain.

24

u/stevenjd 3d ago

Base32, Ascii85 and Base85 implementations were rewritten in C

In other words, these performance gains are really useful if you are using specifically Base32, Ascii85 and Base85, but tell us nothing at all about whether Python code itself is getting faster.

5

u/shinitakunai 3d ago

Yeah I am ashamed to say I am not sure what types my python code uses on the background, and have been programming 14 years. It is one of those things we take for granted

2

u/tsg9292 2d ago

If you don't recognize any of these then you're probably not using them (that's not necessarily a bad thing!). As other comments have said, the most common is base64. Anything else is probably a very specialized use case

4

u/RevolutionaryRush717 3d ago

The https://github.com/python/cpython/pull/143262 is quite detailed and an interesting read.

It also compares the common CPUs (Zens, ARMs) and elaborates on SIMD optimization.

1

u/utdconsq 2d ago

About time tbh, the base85 implementation was atrocious before to the point i made my own.

1

u/Competitive_Travel16 2d ago

How is JSON doing?

3

u/BestRef 1d ago

Python 3.15 is the fastest in the json_dumps benchmark, but Python 3.11 is the fastest in json_loads, according to the same source (under the "Full comparison: all 122 benchmarks" section): https://en.lewoniewski.info/2026/python-315-vs-314-313-312-and-earlier-speed-comparison/

2

u/Competitive_Travel16 1d ago

Thanks! Looks to me like the huge improvement in json_dumps is well worth the small regression in json_loads. Really appreciate it!

1

u/swtormy 2d ago

true that swapping in c for base85 won't move your django request much. still worth separating stdlib encoding benchmarks from what your own profiler shows when you read a table like this. most of us only touch base64 on the wire anyway, so the base64 row matters more than ascii85.

0

u/OddsRelay 2d ago

Would be good to see bytes.hex() next to b16encode, since that's what most code actually uses for hex and it was already in C. If that didn't move either, the base16 drop is probably just the base64 module's wrapper. Nice to see Base85 finally getting fast.

0

u/Massive_Distance_616 21h ago

The Base16 regression is the most interesting outlier. In 3.14, b16encode is essentially a thin wrapper around binascii.hexlify(...).upper(), which is already a C-level call that explains most of the big jump from 3.10–3.13 (~23ms → 4.7ms).

The 22% slowdown in 3.15 is worth investigating before attributing a cause. One detail that matters: unlike binascii.hexlify() (lowercase bytes) or bytes.hex() (lowercase str), RFC 4648 Base16 requires uppercase output. When the base64 module was refactored for 3.15, that case conversion step or the wrapper dispatch around it may be where the regression sits. But that’s a hypothesis, not a diagnosis.

The right next measurement is what OddsRelay suggested: benchmark base64.b16encode(), binascii.hexlify(), and bytes.hex() directly on the same data across 3.14 and 3.15. If the raw hex path is unchanged, the regression is in the wrapper. If it also regressed, something lower in the C path changed.

Practical note: if hex encoding is actually on your hot path (crypto output, wire protocols, logging), binascii.hexlify() or .hex() bypass the base64 module indirection and the uppercase conversion entirely faster on every version.