import heapq
import random
import time
from dataclasses import dataclass
from collections import namedtuple
from typing import NamedTuple
# Configuration
N = 100_000
random.seed(0)
keys = [
(
(-random.randint(0, 1000), -random.randint(0, 1000),
random.randint(0, 1000), -random.randint(0, 1000)),
i,
random.randint(0, 1000)
)
for i in range(N)
]
# 1. Raw tuples (already in 'keys')
tuple_items = keys.copy()
# 2. collections.namedtuple instances
TaskNT = namedtuple('TaskNT', ['key', 'taskId', 'userId'])
namedtuple_items = [TaskNT(k, t, u) for k, t, u in keys]
# 3. typing.NamedTuple instances
class TaskTNT(NamedTuple):
key: tuple
taskId: int
userId: int
typing_namedtuple_items = [TaskTNT(k, t, u) for k, t, u in keys]
# 4. Dataclass instances
@dataclass(order=True)
class TaskDC:
key: tuple
taskId: int
userId: int
dataclass_items = [TaskDC(k, t, u) for k, t, u in keys]
# 5. Dataclass with slots instances
@dataclass(order=True, slots=True)
class TaskDCS:
key: tuple
taskId: int
userId: int
dataclass_slots_items = [TaskDCS(k, t, u) for k, t, u in keys]
def bench_tuple():
h = []
for item in tuple_items:
heapq.heappush(h, item)
for _ in range(len(tuple_items)):
heapq.heappop(h)
def bench_namedtuple():
h = []
for item in namedtuple_items:
heapq.heappush(h, item)
for _ in range(len(namedtuple_items)):
heapq.heappop(h)
def bench_typing_namedtuple():
h = []
for item in typing_namedtuple_items:
heapq.heappush(h, item)
for _ in range(len(typing_namedtuple_items)):
heapq.heappop(h)
def bench_dataclass():
h = []
for item in dataclass_items:
heapq.heappush(h, item)
for _ in range(len(dataclass_items)):
heapq.heappop(h)
def bench_dataclass_slots():
h = []
for item in dataclass_slots_items:
heapq.heappush(h, item)
for _ in range(len(dataclass_slots_items)):
heapq.heappop(h)
# Run benchmarks
benchmarks = [
('tuple', bench_tuple),
('namedtuple', bench_namedtuple),
('typing.NamedTuple', bench_typing_namedtuple),
('dataclass', bench_dataclass),
('dataclass(slots)', bench_dataclass_slots)
]
results = []
for name, func in benchmarks:
start = time.perf_counter()
func()
duration = time.perf_counter() - start
results.append((name, duration))
# Display results
for name, duration in results:
print(f"{name:20s}: {duration:.4f} seconds")