Helpers API¶
Overview
canfar.helpers.distributed partitions an ordered list across Session
replicas. Each replica container receives REPLICA_ID and REPLICA_COUNT
in its environment, and these functions read them by default.
Practical examples¶
Stripe: take every Nth item with an offset¶
from canfar.helpers import distributed
# Assume REPLICA_ID=2 and REPLICA_COUNT=4
# Replica 2 (1-based) will see indices 1, 5, 9, ...
items = list(range(12))
shard = list(distributed.stripe(items, replica=2, total=4))
print(shard) # [1, 5, 9]
Chunk: contiguous chunks of roughly equal size¶
from canfar.helpers import distributed
# Assume 10 items, 4 replicas
items = list(range(10))
# Replica 1 gets [0,1], 2->[2,3], 3->[4,5], 4->[6,7,8,9] (last takes remainder)
print(list(distributed.chunk(items, replica=1, total=4)))
print(list(distributed.chunk(items, replica=4, total=4)))
Sparse distribution
When items < replicas, chunk assigns exactly one item to each of the first len(items) replicas, and later replicas get nothing. This avoids duplication.
Using container-provided environment variables¶
# Inside CANFAR container replicas, you can omit replica/total and read from env
from canfar.helpers import distributed
work = list(range(1000))
for item in distributed.chunk(work):
process(item)
Validation and errors¶
chunk() requires total > 0 and 1 <= replica <= total, raising
ValueError otherwise. stripe() intentionally keeps a looser compatibility
contract: replica < 1 yields no items, even when total <= 0. For a positive
replica, total <= 0 raises ValueError; otherwise replica > total yields
no items. Both functions use REPLICA_ID and REPLICA_COUNT when
their corresponding arguments are omitted, defaulting to one replica when the
environment is absent.
API reference¶
canfar.helpers.distributed ¶
Helper functions for distributed computing.
stripe ¶
stripe(
iterable: Iterable[T], replica: int | None = None, total: int | None = None
) -> Iterator[T]
Return every total-th item from iterable with a replica offset.
Uses 1-based replica indexing to match REPLICA_ID in CANFAR
containers. Replica 1 receives indices 0, total, 2 * total, …;
replica 2 receives indices 1, total + 1, …; and so on.
Unlike chunk, stripe returns no items when replica < 1,
even when total <= 0. For a positive replica, total <= 0 raises
ValueError; otherwise replica > total returns no items.
| PARAMETER | DESCRIPTION |
|---|---|
iterable
|
The iterable to stripe across replicas.
TYPE:
|
replica
|
The replica number (1-based). Defaults to
TYPE:
|
total
|
The total number of replicas. Defaults to
TYPE:
|
| YIELDS | DESCRIPTION |
|---|---|
T
|
Items assigned to this replica. |
Examples:
>>> from canfar.helpers import distributed
>>> list(distributed.stripe(range(10), replica=1, total=3))
[0, 3, 6, 9]
>>> list(distributed.stripe(range(10), replica=2, total=3))
[1, 4, 7]
>>> list(distributed.stripe(range(100), replica=1, total=10))
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
chunk ¶
chunk(
iterable: Iterable[T], replica: int | None = None, total: int | None = None
) -> Iterator[T]
Return the replica-th contiguous chunk of iterable.
Splits iterable into total roughly equal contiguous chunks using
1-based replica indexing to match REPLICA_ID in CANFAR containers.
Distribution behavior:
- Standard (
len(items) >= total): Items are divided into equal-sized chunks; the last replica receives any remainder. - Sparse (
len(items) < total): Each of the firstlen(items)replicas receives exactly one item; remaining replicas get nothing.
| PARAMETER | DESCRIPTION |
|---|---|
iterable
|
The iterable to distribute across replicas.
TYPE:
|
replica
|
The replica number (1-based). Must be >= 1 and <=
TYPE:
|
total
|
The total number of replicas. Must be > 0. Defaults to
TYPE:
|
| YIELDS | DESCRIPTION |
|---|---|
T
|
Items assigned to this replica. |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If |
Examples:
>>> from canfar.helpers import distributed
>>> list(distributed.chunk(range(12), replica=1, total=3))
[0, 1, 2, 3]
>>> list(distributed.chunk(range(10), replica=4, total=4))
[6, 7, 8, 9]
>>> list(distributed.chunk([1, 2, 3], replica=2, total=5))
[2]