Last active
July 28, 2022 11:17
-
-
Save nmichlo/58d97b2cd0ebd34ace66daeb5c834600 to your computer and use it in GitHub Desktop.
python basic container types benchmark
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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