Skip to content

Instantly share code, notes, and snippets.

@nmichlo
Last active July 28, 2022 11:17
Show Gist options
  • Save nmichlo/58d97b2cd0ebd34ace66daeb5c834600 to your computer and use it in GitHub Desktop.
Save nmichlo/58d97b2cd0ebd34ace66daeb5c834600 to your computer and use it in GitHub Desktop.
python basic container types benchmark
"""
Benchmark of different python calls:
TL;DR:
- don't use dict(), dataclasses or namedtuples
- use {...}, [...], (...)
- tuples are fastest
- args are faster than kwargs for dataclasses and namedtuples
RESULTS:
- 10_000_000 repeats
- py3.8 - macbook pro 16-inch, 2019, 2.3 GHz 8-Core Intel Core i9, 16 GB 2667 MHz DDR4
* python 3.7.13:
tuples 3 ((...)): 911.170ms
tuples 2 ((...)): 642.023ms
tuples 1 ((...)): 574.384ms
lists 3 ([...]): 1081.511ms
lists 2 ([...]): 787.426ms
lists 1 ([...]): 760.946ms
dicts 3 ({...}): 1535.036ms
dicts 2 ({...}): 1109.810ms
dicts 1 ({...}): 839.998ms
dicts 3 (dict(...)): 3122.568ms
dicts 2 (dict(...)): 2556.631ms
dicts 1 (dict(...)): 2146.051ms
dataclass 3 (args): 4666.431ms
dataclass 2 (args): 3432.309ms
dataclass 1 (args): 2762.790ms
dataclass 3 (kwargs): 5738.825ms
dataclass 2 (kwargs): 4356.591ms
dataclass 1 (kwargs): 3428.027ms
namedtuple 3 (args): 3844.480ms
namedtuple 2 (args): 3515.346ms
namedtuple 1 (args): 3171.654ms
namedtuple 3 (kwargs): 4827.335ms
namedtuple 2 (kwargs): 4308.437ms
namedtuple 1 (kwargs): 4010.129ms
fn_any_kwargs 3: 2030.155ms
fn_any_kwargs 2: 1858.870ms
fn_any_kwargs 1: 1417.506ms
fn_any_args 3: 1512.862ms
fn_any_args 2: 1240.486ms
fn_any_args 1: 1129.123ms
fn_any_args_kwargs 3 (kwargs): 2042.676ms
fn_any_args_kwargs 2 (kwargs): 1876.266ms
fn_any_args_kwargs 1 (kwargs): 1446.067ms
fn_any_args_kwargs 3 (args): 1674.896ms
fn_any_args_kwargs 2 (args): 1651.908ms
fn_any_args_kwargs 1 (args): 1365.480ms
fn_either 3 (kwargs): 1483.343ms
fn_either 2 (kwargs): 1204.456ms
fn_either 1 (kwargs): 1042.316ms
fn_either 3 (args): 1307.679ms
fn_either 2 (args): 1032.563ms
fn_either 1 (args): 894.063ms
fn_kwargs 3: 1470.908ms
fn_kwargs 2: 1350.370ms
fn_kwargs 1: 1060.273ms
fn_args 3: N/A
fn_args 2: N/A
fn_args 1: N/A
* python 3.8.13:
tuples 3 ((...)): 876.265ms
tuples 2 ((...)): 609.160ms
tuples 1 ((...)): 515.247ms
lists 3 ([...]): 1024.264ms
lists 2 ([...]): 757.024ms
lists 1 ([...]): 652.607ms
dicts 3 ({...}): 1360.866ms
dicts 2 ({...}): 930.191ms
dicts 1 ({...}): 709.264ms
dicts 3 (dict(...)): 2817.133ms
dicts 2 (dict(...)): 2244.777ms
dicts 1 (dict(...)): 1877.986ms
dataclass 3 (args): 3535.272ms
dataclass 2 (args): 3239.146ms
dataclass 1 (args): 2427.845ms
dataclass 3 (kwargs): 4724.288ms
dataclass 2 (kwargs): 4147.749ms
dataclass 1 (kwargs): 3144.072ms
namedtuple 3 (args): 3505.926ms
namedtuple 2 (args): 3495.072ms
namedtuple 1 (args): 3116.601ms
namedtuple 3 (kwargs): 4727.019ms
namedtuple 2 (kwargs): 4330.028ms
namedtuple 1 (kwargs): 3804.334ms
fn_any_kwargs 3: 1951.519ms
fn_any_kwargs 2: 1751.193ms
fn_any_kwargs 1: 1348.928ms
fn_any_args 3: 1428.089ms
fn_any_args 2: 1391.278ms
fn_any_args 1: 1132.014ms
fn_any_args_kwargs 3 (kwargs): 2023.204ms
fn_any_args_kwargs 2 (kwargs): 1796.902ms
fn_any_args_kwargs 1 (kwargs): 1407.309ms
fn_any_args_kwargs 3 (args): 1535.338ms
fn_any_args_kwargs 2 (args): 1485.984ms
fn_any_args_kwargs 1 (args): 1266.931ms
fn_either 3 (kwargs): 1457.432ms
fn_either 2 (kwargs): 1210.102ms
fn_either 1 (kwargs): 1056.017ms
fn_either 3 (args): 1279.387ms
fn_either 2 (args): 1028.427ms
fn_either 1 (args): 896.738ms
fn_kwargs 3: 1454.188ms
fn_kwargs 2: 1219.968ms
fn_kwargs 1: 1055.629ms
fn_args 3: 1300.413ms
fn_args 2: 1043.031ms
fn_args 1: 911.367ms
* python 3.9.11
tuples 3 ((...)): 735.943ms
tuples 2 ((...)): 621.640ms
tuples 1 ((...)): 540.026ms
lists 3 ([...]): 864.660ms
lists 2 ([...]): 771.977ms
lists 1 ([...]): 679.782ms
dicts 3 ({...}): 1253.002ms
dicts 2 ({...}): 1022.668ms
dicts 1 ({...}): 749.312ms
dicts 3 (dict(...)): 1770.630ms
dicts 2 (dict(...)): 1547.290ms
dicts 1 (dict(...)): 1323.875ms
dataclass 3 (args): 3601.850ms
dataclass 2 (args): 3086.705ms
dataclass 1 (args): 2458.365ms
dataclass 3 (kwargs): 4846.862ms
dataclass 2 (kwargs): 4094.181ms
dataclass 1 (kwargs): 3301.048ms
namedtuple 3 (args): 3484.529ms
namedtuple 2 (args): 3190.624ms
namedtuple 1 (args): 2999.048ms
namedtuple 3 (kwargs): 4813.248ms
namedtuple 2 (kwargs): 4410.435ms
namedtuple 1 (kwargs): 3924.033ms
fn_any_kwargs 3: 2071.355ms
fn_any_kwargs 2: 1700.936ms
fn_any_kwargs 1: 1426.413ms
fn_any_args 3: 1491.670ms
fn_any_args 2: 1247.413ms
fn_any_args 1: 1145.883ms
fn_any_args_kwargs 3 (kwargs): 2114.520ms
fn_any_args_kwargs 2 (kwargs): 1714.040ms
fn_any_args_kwargs 1 (kwargs): 1471.142ms
fn_any_args_kwargs 3 (args): 1609.508ms
fn_any_args_kwargs 2 (args): 1367.102ms
fn_any_args_kwargs 1 (args): 1268.760ms
fn_either 3 (kwargs): 1437.779ms
fn_either 2 (kwargs): 1182.390ms
fn_either 1 (kwargs): 1057.241ms
fn_either 3 (args): 1273.430ms
fn_either 2 (args): 1005.822ms
fn_either 1 (args): 938.268ms
fn_kwargs 3: 1401.010ms
fn_kwargs 2: 1187.778ms
fn_kwargs 1: 1031.330ms
fn_args 3: 1276.567ms
fn_args 2: 1019.057ms
fn_args 1: 951.962ms
* python 3.10.3
tuples 3 ((...)): 744.234ms
tuples 2 ((...)): 665.432ms
tuples 1 ((...)): 559.751ms
lists 3 ([...]): 878.768ms
lists 2 ([...]): 810.359ms
lists 1 ([...]): 688.271ms
dicts 3 ({...}): 1300.272ms
dicts 2 ({...}): 1052.768ms
dicts 1 ({...}): 769.205ms
dicts 3 (dict(...)): 1980.561ms
dicts 2 (dict(...)): 1574.483ms
dicts 1 (dict(...)): 1322.526ms
dataclass 3 (args): 3676.438ms
dataclass 2 (args): 3141.672ms
dataclass 1 (args): 2568.273ms
dataclass 3 (kwargs): 5065.887ms
dataclass 2 (kwargs): 4364.485ms
dataclass 1 (kwargs): 3473.279ms
namedtuple 3 (args): 3604.209ms
namedtuple 2 (args): 3352.057ms
namedtuple 1 (args): 3139.613ms
namedtuple 3 (kwargs): 4954.527ms
namedtuple 2 (kwargs): 4399.748ms
namedtuple 1 (kwargs): 3866.145ms
fn_any_kwargs 3: 2095.312ms
fn_any_kwargs 2: 1708.130ms
fn_any_kwargs 1: 1423.038ms
fn_any_args 3: 1570.529ms
fn_any_args 2: 1271.360ms
fn_any_args 1: 1170.911ms
fn_any_args_kwargs 3 (kwargs): 2239.692ms
fn_any_args_kwargs 2 (kwargs): 1823.980ms
fn_any_args_kwargs 1 (kwargs): 1526.646ms
fn_any_args_kwargs 3 (args): 1795.120ms
fn_any_args_kwargs 2 (args): 1490.370ms
fn_any_args_kwargs 1 (args): 1438.359ms
fn_either 3 (kwargs): 1453.150ms
fn_either 2 (kwargs): 1163.793ms
fn_either 1 (kwargs): 1034.745ms
fn_either 3 (args): 1327.771ms
fn_either 2 (args): 1073.208ms
fn_either 1 (args): 972.357ms
fn_kwargs 3: 1459.959ms
fn_kwargs 2: 1227.675ms
fn_kwargs 1: 1051.762ms
fn_args 3: 1320.032ms
fn_args 2: 1077.129ms
fn_args 1: 957.986ms
* python 3.11.0a6
tuples 3 ((...)): 1114.585ms
tuples 2 ((...)): 827.463ms
tuples 1 ((...)): 691.723ms
lists 3 ([...]): 1239.550ms
lists 2 ([...]): 965.200ms
lists 1 ([...]): 823.352ms
dicts 3 ({...}): 1834.606ms
dicts 2 ({...}): 1349.323ms
dicts 1 ({...}): 1049.018ms
dicts 3 (dict(...)): 2378.122ms
dicts 2 (dict(...)): 1961.002ms
dicts 1 (dict(...)): 1653.343ms
dataclass 3 (args): 3205.463ms
dataclass 2 (args): 2824.220ms
dataclass 1 (args): 2545.679ms
dataclass 3 (kwargs): 4561.344ms
dataclass 2 (kwargs): 3854.333ms
dataclass 1 (kwargs): 3274.043ms
namedtuple 3 (args): 4108.129ms
namedtuple 2 (args): 3660.144ms
namedtuple 1 (args): 3466.473ms
namedtuple 3 (kwargs): 5472.833ms
namedtuple 2 (kwargs): 4756.481ms
namedtuple 1 (kwargs): 4232.152ms
fn_any_kwargs 3: 2480.596ms
fn_any_kwargs 2: 2061.839ms
fn_any_kwargs 1: 1536.806ms
fn_any_args 3: 1659.416ms
fn_any_args 2: 1376.440ms
fn_any_args 1: 1254.563ms
fn_any_args_kwargs 3 (kwargs): 2479.994ms
fn_any_args_kwargs 2 (kwargs): 1994.122ms
fn_any_args_kwargs 1 (kwargs): 1634.321ms
fn_any_args_kwargs 3 (args): 1873.374ms
fn_any_args_kwargs 2 (args): 1598.465ms
fn_any_args_kwargs 1 (args): 1469.278ms
fn_either 3 (kwargs): 1567.918ms
fn_either 2 (kwargs): 1294.876ms
fn_either 1 (kwargs): 1305.250ms
fn_either 3 (args): 1352.392ms
fn_either 2 (args): 1106.356ms
fn_either 1 (args): 969.338ms
fn_kwargs 3: 1571.886ms
fn_kwargs 2: 1275.929ms
fn_kwargs 1: 1095.139ms
fn_args 3: 1381.734ms
fn_args 2: 1085.077ms
fn_args 1: 975.141ms
"""
import contextlib
import time
from dataclasses import dataclass
from typing import NamedTuple
@contextlib.contextmanager
def Timer(name: str):
t = time.time_ns()
try:
yield
finally:
t = (time.time_ns() - t) / 1000_000
print(f'{name}: {t:.3f}ms')
# TYPES:
@dataclass
class DcItem3:
a: int
b: int
c: int
@dataclass
class DcItem2:
a: int
b: int
@dataclass
class DcItem1:
a: int
class NtItem3(NamedTuple):
a: int
b: int
c: int
class NtItem2(NamedTuple):
a: int
b: int
class NtItem1(NamedTuple):
a: int
# TESTS:
n = 10_000_000
# - tuples
with Timer('tuples 3 ((...))'):
for i in range(n):
(i, i, i)
with Timer('tuples 2 ((...))'):
for i in range(n):
(i, i)
with Timer('tuples 1 ((...))'):
for i in range(n):
(i,)
# - lists
with Timer('lists 3 ([...])'):
for i in range(n):
[i, i, i]
with Timer('lists 2 ([...])'):
for i in range(n):
[i, i]
with Timer('lists 1 ([...])'):
for i in range(n):
[i]
# - dicts
with Timer('dicts 3 ({...})'):
for i in range(n):
{"a": i, 'b': i, "c": i}
with Timer('dicts 2 ({...})'):
for i in range(n):
{"a": i, 'b': i}
with Timer('dicts 1 ({...})'):
for i in range(n):
{"a": i}
# - dicts (kwargs)
with Timer('dicts 3 (dict(...))'):
for i in range(n):
dict(a=i, b=i, c=i)
with Timer('dicts 2 (dict(...))'):
for i in range(n):
dict(a=i, b=i)
with Timer('dicts 1 (dict(...))'):
for i in range(n):
dict(a=i)
# - dataclass (args)
with Timer('dataclass 3 (args)'):
for i in range(n):
DcItem3(i, i, i)
with Timer('dataclass 2 (args)'):
for i in range(n):
DcItem2(i, i)
with Timer('dataclass 1 (args)'):
for i in range(n):
DcItem1(i)
# - dataclass (kwargs)
with Timer('dataclass 3 (kwargs)'):
for i in range(n):
DcItem3(a=i, b=i, c=i)
with Timer('dataclass 2 (kwargs)'):
for i in range(n):
DcItem2(a=i, b=i)
with Timer('dataclass 1 (kwargs)'):
for i in range(n):
DcItem1(a=i)
# - namedtuple (args)
with Timer('namedtuple 3 (args)'):
for i in range(n):
NtItem3(i, i, i)
with Timer('namedtuple 2 (args)'):
for i in range(n):
NtItem2(i, i)
with Timer('namedtuple 1 (args)'):
for i in range(n):
NtItem1(i)
# - namedtuple (kwargs)
with Timer('namedtuple 3 (kwargs)'):
for i in range(n):
NtItem3(a=i, b=i, c=i)
with Timer('namedtuple 2 (kwargs)'):
for i in range(n):
NtItem2(a=i, b=i)
with Timer('namedtuple 1 (kwargs)'):
for i in range(n):
NtItem1(a=i)
# - func calls
def fn_any_kwargs(**kwargs): pass
def fn_any_args(*args): pass
def fn_any_args_kwargs(*args, **kwargs): pass
def fn_either_1(a): pass
def fn_either_2(a, b): pass
def fn_either_3(a, b, c): pass
def fn_kwargs_1(*, a): pass
def fn_kwargs_2(*, a, b): pass
def fn_kwargs_3(*, a, b, c): pass
def fn_args_1(a, /): pass
def fn_args_2(a, b, /): pass
def fn_args_3(a, b, c, /): pass
with Timer('fn_any_kwargs 3'):
for i in range(n):
fn_any_kwargs(a=i, b=i, c=i)
with Timer('fn_any_kwargs 2'):
for i in range(n):
fn_any_kwargs(a=i, b=i)
with Timer('fn_any_kwargs 1'):
for i in range(n):
fn_any_kwargs(a=i)
with Timer('fn_any_args 3'):
for i in range(n):
fn_any_args(i, i, i)
with Timer('fn_any_args 2'):
for i in range(n):
fn_any_args(i, i)
with Timer('fn_any_args 1'):
for i in range(n):
fn_any_args(i)
with Timer('fn_any_args_kwargs 3 (kwargs)'):
for i in range(n):
fn_any_args_kwargs(a=i, b=i, c=i)
with Timer('fn_any_args_kwargs 2 (kwargs)'):
for i in range(n):
fn_any_args_kwargs(a=i, b=i)
with Timer('fn_any_args_kwargs 1 (kwargs)'):
for i in range(n):
fn_any_args_kwargs(a=i)
with Timer('fn_any_args_kwargs 3 (args)'):
for i in range(n):
fn_any_args_kwargs(i, i, i)
with Timer('fn_any_args_kwargs 2 (args)'):
for i in range(n):
fn_any_args_kwargs(i, i)
with Timer('fn_any_args_kwargs 1 (args)'):
for i in range(n):
fn_any_args_kwargs(i)
with Timer('fn_either 3 (kwargs)'):
for i in range(n):
fn_either_3(a=i, b=i, c=i)
with Timer('fn_either 2 (kwargs)'):
for i in range(n):
fn_either_2(a=i, b=i)
with Timer('fn_either 1 (kwargs)'):
for i in range(n):
fn_either_1(a=i)
with Timer('fn_either 3 (args)'):
for i in range(n):
fn_either_3(i, i, i)
with Timer('fn_either 2 (args)'):
for i in range(n):
fn_either_2(i, i)
with Timer('fn_either 1 (args)'):
for i in range(n):
fn_either_1(i)
with Timer('fn_kwargs 3'):
for i in range(n):
fn_kwargs_3(a=i, b=i, c=i)
with Timer('fn_kwargs 2'):
for i in range(n):
fn_kwargs_2(a=i, b=i)
with Timer('fn_kwargs 1'):
for i in range(n):
fn_kwargs_1(a=i)
with Timer('fn_args 3'):
for i in range(n):
fn_args_3(i, i, i)
with Timer('fn_args 2'):
for i in range(n):
fn_args_2(i, i)
with Timer('fn_args 1'):
for i in range(n):
fn_args_1(i)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment