This article describes the performance testing results of Python 3.12 compared to Python 3.11. A total of 91 various benchmark tests were conducted on computers with the AMD Ryzen 7000 series and the 13th-generation of Intel Core processors for desktops, laptops or mini PCs.
All tests were run on Windows 11 computers using the pyperformance 1.0.9 library in Python 3.11.6 and Python 3.12.0 (both 64-bit versions).
AMD Ryzen 7000 Series Desktop Processor
The first part of testing involved a desktop computer with an AMD Ryzen 9 7900 processor, RAM DDR5, and an M.2 PCIe Gen4 NVMe drive. The table below shows the results of 91 tests performed using Python 3.11 (as a reference) and Python 3.12 on this device.
Benchmark | Python 3.11 | Python 3.12 |
---|---|---|
2to3 | 191 ms | 202 ms (1.06x slower) |
async_generators | 198 ms | 268 ms (1.35x slower) |
async_tree_cpu_io_mixed | 580 ms | 516 ms (1.12x faster) |
async_tree_cpu_io_mixed_tg | 521 ms | 512 ms (1.02x faster) |
async_tree_io | 949 ms | 864 ms (1.10x faster) |
async_tree_io_tg | 930 ms | 892 ms (1.04x faster) |
async_tree_memoization | 420 ms | 386 ms (1.09x faster) |
async_tree_memoization_tg | 394 ms | 378 ms (1.04x faster) |
async_tree_none | 340 ms | 316 ms (1.07x faster) |
async_tree_none_tg | 300 ms | 292 ms (1.03x faster) |
asyncio_tcp | 708 ms | 476 ms (1.49x faster) |
asyncio_tcp_ssl | 2.02 sec | 1.90 sec (1.07x faster) |
bench_mp_pool | 54.9 ms | 63.8 ms (1.16x slower) |
bench_thread_pool | 687 us | 694 us (1.01x slower) |
chameleon | 5.23 ms | 5.25 ms (not significant) |
chaos | 45.7 ms | 45.5 ms (not significant) |
comprehensions | 14.4 us | 14.3 us (not significant) |
coroutines | 16.9 ms | 16.9 ms (not significant) |
coverage | 141 ms | 239 ms (1.69x slower) |
create_gc_cycles | 521 us | 537 us (1.03x slower) |
crypto_pyaes | 48.3 ms | 49.6 ms (1.03x slower) |
dask | 235 ms | 241 ms (1.03x slower) |
deepcopy | 225 us | 229 us (1.02x slower) |
deepcopy_memo | 25.1 us | 26.1 us (1.04x slower) |
deepcopy_reduce | 2.02 us | 2.11 us (1.05x slower) |
deltablue | 2.63 ms | 2.48 ms (1.06x faster) |
django_template | 23.0 ms | 23.4 ms (1.02x slower) |
docutils | 1.39 sec | 1.46 sec (1.05x slower) |
fannkuch | 240 ms | 254 ms (1.06x slower) |
float | 53.5 ms | 59.6 ms (1.11x slower) |
gc_traversal | 1.25 ms | 1.26 ms (1.01x slower) |
generators | 41.0 ms | 26.6 ms (1.55x faster) |
genshi_text | 16.6 ms | 16.2 ms (1.03x faster) |
genshi_xml | 95.9 ms | 97.9 ms (1.03x faster) |
hexiom | 4.39 ms | 4.57 ms (1.04x slower) |
html5lib | 31.2 ms | 33.3 ms (1.07x slower) |
json_dumps | 7.72 ms | 5.77 ms (1.34x faster) |
json_loads | 12.7 us | 13.5 us (1.06x slower) |
logging_format | 6.35 us | 6.62 us (1.04x slower) |
logging_silent | 71.6 ns | 70.5 ns (1.02x faster) |
logging_simple | 6.00 us | 6.24 us (1.04x slower) |
mako | 7.49 ms | 7.76 ms (1.04x slower) |
mdp | 1.62 sec | 1.62 sec (not significant) |
meteor_contest | 65.9 ms | 67.4 ms (1.02x slower) |
nbody | 73.6 ms | 87.0 ms (1.18x slower) |
nqueens | 60.3 ms | 61.7 ms (1.02x slower) |
pathlib | 79.9 ms | 91.9 ms (1.15x slower) |
pickle | 6.66 us | 7.11 us (1.07x slower) |
pickle_dict | 18.3 us | 18.9 us (1.03x slower) |
pickle_list | 2.59 us | 2.73 us (1.05x slower) |
pickle_pure_python | 191 us | 198 us (1.03x slower) |
pidigits | 136 ms | 138 ms (1.02x slower) |
pprint_pformat | 983 ms | 1.03 sec (1.04x slower) |
pprint_safe_repr | 479 ms | 506 ms (1.06x slower) |
pyflate | 293 ms | 315 ms (1.07x slower) |
python_startup | 15.2 ms | 15.6 ms (1.02x slower) |
python_startup_no_site | 12.5 ms | 13.1 ms (1.04x slower) |
raytrace | 204 ms | 210 ms (1.03x slower) |
regex_compile | 77.1 ms | 83.1 ms (1.08x slower) |
regex_dna | 103 ms | 103 ms (not significant) |
regex_effbot | 1.64 ms | 1.74 ms (1.06x slower) |
regex_v8 | 14.7 ms | 14.4 ms (1.03x faster) |
richards | 29.8 ms | 31.2 ms (1.05x slower) |
richards_super | 37.0 ms | 34.6 ms (1.07x faster) |
scimark_fft | 214 ms | 220 ms (1.03x slower) |
scimark_lu | 68.7 ms | 75.3 ms (1.10x slower) |
scimark_monte_carlo | 44.2 ms | 48.3 ms (1.09x slower) |
scimark_sor | 80.4 ms | 91.7 ms (1.14x slower) |
scimark_sparse_mat_mult | 3.29 ms | 3.32 ms (not significant) |
spectral_norm | 75.7 ms | 84.7 ms (1.12x slower) |
sqlglot_normalize | 178 ms | 186 ms (1.04x slower) |
sqlglot_optimize | 32.3 ms | 33.9 ms (1.05x slower) |
sqlglot_parse | 891 us | 861 us (1.04x faster) |
sqlglot_transpile | 1.06 ms | 1.05 ms (not significant) |
sqlite_synth | 1.41 us | 1.49 us (1.06x slower) |
sympy_expand | 248 ms | 247 ms (1.00x faster) |
sympy_integrate | 11.8 ms | 11.8 ms (not significant) |
sympy_str | 152 ms | 154 ms (1.01x slower) |
sympy_sum | 86.4 ms | 83.3 ms (1.04x faster) |
telco | 3.91 ms | 4.26 ms (1.09x slower) |
tomli_loads | 1.46 sec | 1.53 sec (1.04x slower) |
tornado_http | 86.9 ms | 86.2 ms (1.01x faster) |
typing_runtime_protocols | 307 us | 102 us (2.99x faster) |
unpack_sequence | 35.1 ns | 53.4 ns (1.52x slower) |
unpickle | 8.13 us | 8.54 us (1.05x slower) |
unpickle_list | 2.86 us | 2.80 us (1.02x faster) |
unpickle_pure_python | 150 us | 149 us (1.01x faster) |
xml_etree_generate | 53.6 ms | 60.4 ms (1.13x slower) |
xml_etree_iterparse | 60.0 ms | 59.1 ms (1.02x faster) |
xml_etree_parse | 82.3 ms | 78.4 ms (1.05x faster) |
xml_etree_process | 38.4 ms | 42.3 ms (1.10x slower) |
Result (geometric mean) | 1.01x slower |
The result shows that Python 3.12 has the best performance results over Python 3.11 in the following tests: typing_runtime_protocols (2.99x faster), generators (1.55x faster), asyncio_tcp (1.49x faster). However, you may notice a drop in performance in some tests, especially in coverage (1.69x slower), unpack_sequence (1.52x slower), async_generators (1.35x slower).
Additionally, you can examine the performance differences between Python 3.12 and Python 3.11 based on benchmarks belonging to specific groups. The table below shows the geometric mean for benchmarks from separate groups for Python 3.12 compared to Python 3.11.
Group of benchmarks | Python 3.12 to Python 3.11 |
---|---|
apps | 1.03x slower |
asyncio | 1.06x faster |
math | 1.10x slower |
regex | 1.03x slower |
serialize | 1.01x slower |
startup | 1.03x slower |
template | 1.00x faster |
13th Gen Intel Core Mobile Processor
The second part of testing involved a mini PC with an Intel Core i3-1315U Processor (which is also used in laptops), RAM DDR4, and an M.2 PCIe Gen4 NVMe drive. The table below shows the results of 91 tests performed using Python 3.11 (as a reference) and Python 3.12 on this device.
Benchmark | Python 3.11 | Python 3.12 |
---|---|---|
2to3 | 250 ms | 256 ms (1.03x slower) |
async_generators | 208 ms | 269 ms (1.29x slower) |
async_tree_cpu_io_mixed | 615 ms | 558 ms (1.10x faster) |
async_tree_cpu_io_mixed_tg | 566 ms | 562 ms (not significant) |
async_tree_io | 864 ms | 793 ms (1.09x faster) |
async_tree_io_tg | 859 ms | 805 ms (1.07x faster) |
async_tree_memoization | 463 ms | 404 ms (1.15x faster) |
async_tree_memoization_tg | 432 ms | 415 ms (1.04x faster) |
async_tree_none | 373 ms | 334 ms (1.12x faster) |
async_tree_none_tg | 340 ms | 322 ms (1.06x faster) |
asyncio_tcp | 966 ms | 707 ms (1.37x faster) |
asyncio_tcp_ssl | 3.22 sec | 2.24 sec (1.44x faster) |
bench_mp_pool | 87.2 ms | 96.7 ms (1.11x slower) |
bench_thread_pool | 1.13 ms | 1.18 ms (not significant) |
chameleon | 6.01 ms | 5.87 ms (1.02x faster) |
chaos | 55.7 ms | 50.8 ms (1.10x faster) |
comprehensions | 18.4 us | 16.5 us (1.12x faster) |
coroutines | 16.8 ms | 16.3 ms (1.03x faster) |
coverage | 163 ms | 267 ms (1.63x slower) |
create_gc_cycles | 799 us | 782 us (1.02x faster) |
crypto_pyaes | 54.9 ms | 54.2 ms (1.01x faster) |
dask | 379 ms | 366 ms (1.04x faster) |
deepcopy | 282 us | 269 us (1.05x faster) |
deepcopy_memo | 28.9 us | 28.0 us (1.03x faster) |
deepcopy_reduce | 2.35 us | 2.40 us (1.02x slower) |
deltablue | 3.02 ms | 2.46 ms (1.23x faster) |
django_template | 27.6 ms | 26.6 ms (1.04x faster) |
docutils | 1.86 sec | 1.90 sec (1.02x slower) |
fannkuch | 283 ms | 281 ms (1.01x faster) |
float | 62.2 ms | 62.4 ms (not significant) |
gc_traversal | 1.80 ms | 1.85 ms (1.02x slower) |
generators | 38.2 ms | 25.7 ms (1.49x faster) |
genshi_text | 19.5 ms | 18.5 ms (1.06x faster) |
genshi_xml | 118 ms | 103 ms (1.06x faster) |
hexiom | 5.19 ms | 4.74 ms (1.10x faster) |
html5lib | 45.5 ms | 43.6 ms (1.04x faster) |
json_dumps | 8.76 ms | 6.54 ms (1.34x faster) |
json_loads | 16.3 us | 15.9 us (1.03x faster) |
logging_format | 7.67 us | 7.40 us (1.04x faster) |
logging_silent | 81.4 ns | 70.5 ns (1.16x faster) |
logging_simple | 7.25 us | 6.83 us (1.06x faster) |
mako | 8.19 ms | 7.76 ms (1.06x faster) |
mdp | 1.93 sec | 1.81 sec (1.07x faster) |
meteor_contest | 85.9 ms | 88.9 ms (1.03x slower) |
nbody | 82.0 ms | 88.4 ms (1.08x slower) |
nqueens | 73.8 ms | 70.9 ms (1.04x faster) |
pathlib | 73.4 ms | 99.6 ms (1.36x slower) |
pickle | 7.71 us | 8.56 us (1.11x slower) |
pickle_dict | 22.0 us | 22.4 us (1.02x slower) |
pickle_list | 3.23 us | 3.38 us (1.05x slower) |
pickle_pure_python | 229 us | 229 us (not significant) |
pidigits | 169 ms | 171 ms (1.01x slower) |
pprint_pformat | 1.19 sec | 1.23 sec (1.03x slower) |
pprint_safe_repr | 581 ms | 604 ms (1.04x slower) |
pyflate | 359 ms | 352 ms (1.02x faster) |
python_startup | 23.1 ms | 22.5 ms (1.03x faster) |
python_startup_no_site | 19.8 ms | 19.4 ms (1.02x faster) |
raytrace | 233 ms | 225 ms (1.03x faster) |
regex_compile | 102 ms | 101 ms (1.02x faster) |
regex_dna | 136 ms | 134 ms (1.01x faster) |
regex_effbot | 1.72 ms | 1.81 ms (1.05x slower) |
regex_v8 | 15.5 ms | 16.0 ms (1.03x slower) |
richards | 35.0 ms | 31.2 ms (1.12x faster) |
richards_super | 43.1 ms | 35.2 ms (1.22x faster) |
scimark_fft | 212 ms | 207 ms (1.02x faster) |
scimark_lu | 71.5 ms | 69.9 ms (1.02x faster) |
scimark_monte_carlo | 53.3 ms | 50.9 ms (1.05x faster) |
scimark_sor | 87.5 ms | 94.6 ms (1.08x slower) |
scimark_sparse_mat_mult | 2.97 ms | 2.89 ms (1.03x faster) |
spectral_norm | 77.2 ms | 74.3 ms (1.04x faster) |
sqlglot_normalize | 219 ms | 212 ms (1.03x faster) |
sqlglot_optimize | 40.6 ms | 38.9 ms (1.04x faster) |
sqlglot_parse | 1.07 ms | 937 us (1.15x faster) |
sqlglot_transpile | 1.31 ms | 1.18 ms (1.11x faster) |
sqlite_synth | 1.97 us | 2.00 us (1.02x slower) |
sympy_expand | 350 ms | 320 ms (1.09x faster) |
sympy_integrate | 15.9 ms | 14.9 ms (1.07x faster) |
sympy_str | 215 ms | 199 ms (1.08x faster) |
sympy_sum | 118 ms | 104 ms (1.14x faster) |
telco | 4.60 ms | 4.80 ms (1.04x slower) |
tomli_loads | 1.60 sec | 1.59 sec (not significant) |
tornado_http | 116 ms | 116 ms (not significant) |
typing_runtime_protocols | 377 us | 116 us (3.25x faster) |
unpack_sequence | 52.6 ns | 48.7 ns (1.08x faster) |
unpickle | 9.04 us | 9.69 us (1.07x slower) |
unpickle_list | 2.99 us | 3.08 us (1.03x slower) |
unpickle_pure_python | 173 us | 160 us (1.08x faster) |
xml_etree_generate | 62.2 ms | 66.0 ms (1.06x slower) |
xml_etree_iterparse | 75.5 ms | 72.4 ms (1.04x faster) |
xml_etree_parse | 116 ms | 104 ms (1.11x faster) |
xml_etree_process | 42.7 ms | 45.1 ms (1.06x slower) |
Result (geometric mean) | 1.05x faster |
The result shows that Python 3.12 has the best performance results over Python 3.11 in the following tests: typing_runtime_protocols (3.25x faster), generators (1.49x faster), asyncio_tcp_ssl (1.44x faster). However, you may notice a drop in performance in some tests, especially in coverage (1.63x slower), pathlib (1.36x slower), async_generators (1.29x slower).
Additionally, you can examine the performance differences between Python 3.12 and Python 3.11 based on benchmarks belonging to specific groups. The table below shows the geometric mean for benchmarks from separate groups for Python 3.12 compared to Python 3.11.
Group of benchmarks | Python 3.12 to Python 3.11 |
---|---|
apps | 1.00x faster |
asyncio | 1.08x faster |
math | 1.03x slower |
regex | 1.02x slower |
serialize | 1.01x faster |
startup | 1.02x faster |
template | 1.05x faster |