Helpers API¶
Overview
The Helpers API provides utility functions to partition work across replicas of a CANFAR session. Containers receive REPLICA_ID and REPLICA_COUNT environment variables, and these helpers make using them simple and correct.
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¶
replicamust be >= 1 and <=totaltotalmust be > 0
API Reference¶
canfar.helpers.distributed ¶
Helper functions for distributed computing.
stripe ¶
stripe(
iterable: Iterable[T],
replica: int = int(os.environ.get("REPLICA_ID", "1")),
total: int = int(os.environ.get("REPLICA_COUNT", "1")),
) -> 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 does not validate replica or total.
When replica is less than 1, or greater than total, the result is
empty. When total is zero, ValueError is raised.
| 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 = int(os.environ.get("REPLICA_ID", "1")),
total: int = int(os.environ.get("REPLICA_COUNT", "1")),
) -> 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]