Python 3.8 vs Python 3.9 – performance testing

This article describes the performance testing results of Python 3.9 compared to Python 3.8. A total of 89 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.8.10 and Python 3.9.13 (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 89 tests performed using Python 3.8 (as a reference) and Python 3.9 on this device.

Benchmark Python 3.8 Python 3.9
2to3 216 ms 217 ms (not significant)
async_generators 231 ms 221 ms (1.04x faster)
async_tree_cpu_io_mixed 683 ms 682 ms (not significant)
async_tree_io 1.35 sec 1.33 sec (1.01x faster)
async_tree_memoization 552 ms 559 ms (not significant)
async_tree_none 456 ms 479 ms (1.05x slower)
asyncio_tcp 650 ms 619 ms (1.05x faster)
asyncio_tcp_ssl 1.84 sec 1.76 sec (1.04x faster)
bench_mp_pool 55.1 ms 56.7 ms (1.03x slower)
bench_thread_pool 727 us 706 us (1.03x faster)
chameleon 7.19 ms 6.03 ms (1.19x faster)
chaos 60.9 ms 57.6 ms (1.06x faster)
comprehensions 14.3 us 14.5 us (not significant)
coroutines 21.9 ms 21.4 ms (1.02x faster)
coverage 25.4 ms 25.5 ms (not significant)
create_gc_cycles 602 us 635 us (1.05x slower)
crypto_pyaes 65.0 ms 61.8 ms (1.05x faster)
dask 265 ms 269 ms (1.02x slower)
deepcopy 252 us 245 us (1.03x faster)
deepcopy_memo 29.0 us 28.3 us (1.02x faster)
deepcopy_reduce 2.24 us 2.19 us (1.02x faster)
deltablue 4.06 ms 4.00 ms (1.01x faster)
django_template 29.4 ms 28.4 ms (1.03x faster)
docutils 1.54 sec 1.57 sec (1.02x slower)
dulwich_log 43.9 ms 42.7 ms (1.03x faster)
fannkuch 264 ms 263 ms (not significant)
float 67.4 ms 66.6 ms (1.01x faster)
gc_traversal 1.43 ms 1.20 ms (1.19x faster)
generators 33.5 ms 32.8 ms (1.02x faster)
genshi_text 18.7 ms 19.1 ms (1.02x slower)
genshi_xml 139 ms 140 ms (1.08x faster)
hexiom 5.57 ms 5.26 ms (1.06x faster)
html5lib 41.4 ms 41.6 ms (not significant)
json_dumps 8.16 ms 8.28 ms (1.02x slower)
json_loads 15.8 us 14.0 us (1.13x faster)
logging_format 6.29 us 6.22 us (1.01x faster)
logging_silent 104 ns 104 ns (not significant)
logging_simple 5.92 us 5.78 us (1.02x faster)
mako 9.58 ms 9.41 ms (1.02x faster)
mdp 1.64 sec 1.77 sec (1.08x slower)
meteor_contest 64.7 ms 63.7 ms (1.02x faster)
nbody 76.8 ms 80.7 ms (1.05x slower)
nqueens 60.8 ms 57.7 ms (1.05x faster)
pathlib 81.5 ms 80.5 ms (1.01x faster)
pickle 6.68 us 6.98 us (1.04x slower)
pickle_dict 17.9 us 17.9 us (not significant)
pickle_list 2.57 us 2.49 us (1.03x faster)
pickle_pure_python 255 us 250 us (1.02x faster)
pidigits 136 ms 139 ms (1.02x slower)
pprint_pformat 902 ms 900 ms (not significant)
pyflate 394 ms 394 ms (not significant)
python_startup 17.8 ms 17.7 ms (1.01x faster)
python_startup_no_site 13.4 ms 13.2 ms (1.02x faster)
raytrace 272 ms 267 ms (1.02x faster)
regex_compile 88.5 ms 86.8 ms (1.02x faster)
regex_dna 116 ms 106 ms (1.09x faster)
regex_effbot 1.90 ms 1.81 ms (1.05x faster)
regex_v8 15.1 ms 14.9 ms (1.01x faster)
richards 38.3 ms 38.0 ms (1.01x faster)
richards_super 47.1 ms 48.5 ms (1.03x slower)
scimark_fft 212 ms 205 ms (1.03x faster)
scimark_lu 86.3 ms 85.4 ms (1.01x faster)
scimark_monte_carlo 58.1 ms 57.9 ms (not significant)
scimark_sor 104 ms 105 ms (not significant)
scimark_sparse_mat_mult 3.08 ms 3.04 ms (1.01x faster)
spectral_norm 81.9 ms 79.7 ms (1.03x faster)
sqlalchemy_declarative 72.5 ms 72.4 ms (not significant)
sqlalchemy_imperative 8.39 ms 8.55 ms (1.02x slower)
sqlglot_normalize 185 ms 181 ms (1.02x faster)
sqlglot_optimize 35.0 ms 34.6 ms (1.01x faster)
sqlglot_parse 1.17 ms 1.20 ms (1.03x slower)
sqlglot_transpile 1.36 ms 1.36 ms (not significant)
sqlite_synth 1.83 us 1.68 us (1.09x faster)
sympy_expand 255 ms 261 ms (1.03x slower)
sympy_integrate 12.3 ms 12.8 ms (1.04x slower)
sympy_str 155 ms 159 ms (1.02x slower)
sympy_sum 86.3 ms 87.4 ms (1.01x slower)
telco 3.62 ms 3.89 ms (1.07x slower)
tomli_loads 1.65 sec 1.57 sec (1.05x faster)
tornado_http 101 ms 101 ms (not significant)
typing_runtime_protocols 316 us 301 us (1.05x faster)
unpack_sequence 34.3 ns 35.0 ns (1.02x slower)
unpickle 9.60 us 7.90 us (1.21x faster)
unpickle_list 2.70 us 2.87 us (1.06x slower)
unpickle_pure_python 175 us 171 us (1.02x faster)
xml_etree_generate 57.9 ms 53.7 ms (1.08x faster)
xml_etree_iterparse 55.3 ms 55.4 ms (not significant)
xml_etree_parse 85.7 ms 84.1 ms (1.02x faster)
xml_etree_process 44.7 ms 42.9 ms (1.04x faster)
Result (geometric mean) 1.02x faster

The result shows that Python 3.9 has the best performance results over Python 3.8 in the following tests: unpickle (1.21x faster), chameleon (1.19x faster), gc_traversal (1.19x faster). However, you may notice a drop in performance in some tests, especially in genshi_xml (1.08x faster), mdp (1.08x slower), telco (1.07x slower).

Additionally, you can examine the performance differences between Python 3.9 and Python 3.8 based on benchmarks belonging to specific groups. The table below shows the geometric mean for benchmarks from separate groups for Python 3.9 compared to Python 3.8.

Group of benchmarks Python 3.9 to Python 3.8
apps 1.03x faster
asyncio 1.01x slower
math 1.02x slower
regex 1.04x faster
serialize 1.03x faster
startup 1.01x faster
template 1.03x 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 89 tests performed using Python 3.8 (as a reference) and Python 3.9 on this device.

Benchmark Python 3.8 Python 3.9
2to3 286 ms 281 ms (1.02x faster)
async_generators 255 ms 249 ms (1.02x faster)
async_tree_cpu_io_mixed 709 ms 708 ms (not significant)
async_tree_io 1.17 sec 1.17 sec (not significant)
async_tree_memoization 574 ms 583 ms (not significant)
async_tree_none 460 ms 479 ms (1.04x slower)
asyncio_tcp 944 ms 912 ms (1.04x faster)
asyncio_tcp_ssl 2.29 sec 2.24 sec (1.02x faster)
bench_mp_pool 87.9 ms 92.4 ms (1.05x slower)
bench_thread_pool 1.21 ms 1.20 ms (not significant)
chameleon 11.6 ms 6.93 ms (1.67x faster)
chaos 70.1 ms 69.2 ms (1.01x faster)
comprehensions 17.8 us 16.3 us (1.09x faster)
coroutines 28.2 ms 25.4 ms (1.11x faster)
coverage 26.1 ms 25.2 ms (1.03x faster)
create_gc_cycles 861 us 883 us (1.03x slower)
crypto_pyaes 73.8 ms 70.5 ms (1.05x faster)
dask 440 ms 436 ms (not significant)
deepcopy 296 us 288 us (1.03x faster)
deepcopy_memo 32.5 us 31.2 us (1.04x faster)
deepcopy_reduce 2.53 us 2.52 us (not significant)
deltablue 4.49 ms 4.50 ms (not significant)
django_template 34.1 ms 34.6 ms (not significant)
docutils 2.03 sec 2.08 sec (1.02x slower)
dulwich_log 56.7 ms 57.7 ms (1.02x slower)
fannkuch 297 ms 289 ms (1.03x faster)
float 74.7 ms 73.1 ms (1.02x faster)
gc_traversal 1.74 ms 1.69 ms (1.02x faster)
generators 35.5 ms 34.4 ms (1.03x faster)
genshi_text 21.3 ms 21.1 ms (1.01x faster)
genshi_xml 160 ms 157 ms (1.50x faster)
hexiom 6.07 ms 5.86 ms (1.04x faster)
html5lib 55.5 ms 56.1 ms (not significant)
json_dumps 9.12 ms 8.96 ms (1.02x faster)
json_loads 22.6 us 16.5 us (1.37x faster)
logging_format 7.35 us 7.50 us (1.02x slower)
logging_silent 110 ns 110 ns (not significant)
logging_simple 6.94 us 6.97 us (not significant)
mako 11.0 ms 10.5 ms (1.05x faster)
mdp 1.93 sec 1.99 sec (1.03x slower)
meteor_contest 81.6 ms 81.9 ms (not significant)
nbody 78.6 ms 81.5 ms (1.04x slower)
nqueens 73.5 ms 69.8 ms (1.05x faster)
pathlib 75.3 ms 74.6 ms (not significant)
pickle 7.56 us 7.89 us (1.04x slower)
pickle_dict 20.0 us 20.0 us (not significant)
pickle_list 3.07 us 3.01 us (1.02x faster)
pickle_pure_python 295 us 292 us (1.01x faster)
pidigits 167 ms 170 ms (1.02x slower)
pprint_pformat 1.06 sec 1.05 sec (1.01x faster)
pyflate 471 ms 471 ms (not significant)
python_startup 25.1 ms 25.1 ms (not significant)
python_startup_no_site 19.9 ms 19.8 ms (not significant)
raytrace 304 ms 301 ms (1.01x faster)
regex_compile 112 ms 112 ms (not significant)
regex_dna 153 ms 147 ms (1.04x faster)
regex_effbot 1.86 ms 1.78 ms (1.04x faster)
regex_v8 17.1 ms 16.5 ms (1.04x faster)
richards 42.5 ms 41.1 ms (1.04x faster)
richards_super 53.2 ms 51.7 ms (1.03x faster)
scimark_fft 212 ms 211 ms (not significant)
scimark_lu 88.4 ms 87.0 ms (1.02x faster)
scimark_monte_carlo 66.7 ms 65.7 ms (1.02x faster)
scimark_sor 114 ms 111 ms (1.03x faster)
scimark_sparse_mat_mult 2.99 ms 2.95 ms (1.01x faster)
spectral_norm 86.6 ms 86.0 ms (1.01x faster)
sqlalchemy_declarative 115 ms 115 ms (not significant)
sqlalchemy_imperative 13.0 ms 13.3 ms (1.02x slower)
sqlglot_normalize 217 ms 207 ms (1.05x faster)
sqlglot_optimize 41.3 ms 41.0 ms (1.01x faster)
sqlglot_parse 1.39 ms 1.38 ms (1.01x faster)
sqlglot_transpile 1.64 ms 1.62 ms (1.02x faster)
sqlite_synth 2.35 us 2.26 us (1.04x faster)
sympy_expand 336 ms 352 ms (1.05x slower)
sympy_integrate 16.6 ms 16.7 ms (1.01x slower)
sympy_str 207 ms 212 ms (1.02x slower)
sympy_sum 116 ms 115 ms (not significant)
telco 4.24 ms 4.38 ms (1.03x slower)
tomli_loads 1.78 sec 1.75 sec (1.02x faster)
tornado_http 140 ms 142 ms (1.01x slower)
typing_runtime_protocols 374 us 361 us (1.04x faster)
unpack_sequence 39.6 ns 40.9 ns (1.03x slower)
unpickle 10.7 us 9.05 us (1.18x faster)
unpickle_list 2.98 us 2.99 us (not significant)
unpickle_pure_python 233 us 199 us (1.17x faster)
xml_etree_generate 73.5 ms 59.5 ms (1.24x faster)
xml_etree_iterparse 75.3 ms 69.7 ms (1.08x faster)
xml_etree_parse 122 ms 113 ms (1.08x faster)
xml_etree_process 57.7 ms 54.6 ms (1.06x faster)
Result (geometric mean) 1.03x faster

The result shows that Python 3.9 has the best performance results over Python 3.8 in the following tests: chameleon (1.67x faster), genshi_xml (1.50x faster), json_loads (1.37x faster). However, you may notice a drop in performance in some tests, especially in bench_mp_pool (1.05x slower), sympy_expand (1.05x slower), async_tree_none (1.04x slower).

Additionally, you can examine the performance differences between Python 3.9 and Python 3.8 based on benchmarks belonging to specific groups. The table below shows the geometric mean for benchmarks from separate groups for Python 3.9 compared to Python 3.8.

Group of benchmarks Python 3.9 to Python 3.8
apps 1.10x faster
asyncio 1.01x slower
math 1.01x slower
regex 1.03x faster
serialize 1.08x faster
template 1.12x faster
Polski
English
Русский