Concurrency
Threads, channels and shared state, with the sharing rules checked before you run. Every value that crosses a thread boundary must be Send; every value shared by reference must also be Sync — both declared with one annotation and validated by the compiler.
Threads
Lightweight and goroutine-shaped: spawn a closure, get a handle back, join it for the result. Every variable the closure captures must be Send, and the closure itself is moved into the new thread.
Parker exposes the primitive underneath — register for park/unpark, block, and wake by id. An unpark issued before the park makes the next park return immediately, so there is no lost-wakeup window.
Channels
Multi-producer, multi-consumer. Capacity zero is unbounded and never blocks the sender; a positive capacity is bounded and blocks when full. trySend and tryReceive are the non-blocking pair.
Select
Non-deterministic receive across several channels, Go-shaped. Select.recv blocks until any channel yields; Select.tryRecv polls once and reports index == -1 when nothing was ready.
A closed, empty channel yields its own slot index with a null value — the same "zero value on a closed receive" convention, which is how you detect closure inside a select arm. Channels in one call share an element type; use Channel<Dynamic> for heterogeneous selects.
Shared state
Arc gives shared ownership across threads — cloning bumps the refcount rather than copying — and pairs with Mutex when the shared value is also mutable.
The inner type must be Send + Sync to cross a thread boundary at all — the compiler rejects the spawn otherwise, rather than leaving it to a data race at runtime. Atomic covers the cases where a lock is more than you need.
Data-parallel work
WorkerPool is the entry point for anything that iterates a large index range — matmul rows, conv tiles, attention heads, elementwise sweeps.
SpinPool, for kernels called hundreds of times
Spawning and joining OS threads per call dominates when a kernel runs hundreds of times per token. A SpinPool spawns its workers once and re-dispatches through a lock-free protocol, so a dispatch costs a few atomic stores.
Work distribution is chunk-stealing rather than static bands: workers claim row ranges from a shared atomic cursor until the range is exhausted. Static bands lose the join to the slowest core — an E-core band runs three to four times longer than a P-core band — while stealing self-balances heterogeneous cores without knowing the topology.
Topology & affinity
CpuTopology is the low-level primitive WorkerPool is built on, exposed for callers who need fine-grained pinning. One topology per process, queried lazily on first call.
On multi-socket Linux and Windows, one worker is pinned per NUMA node so allocations land first-touch on that node's memory controller.
Node count is 1, every CPU maps to node 0, and binding succeeds as a soft affinity hint. Work runs inline unless you force fanout.
The concurrent package
Drop behavior for runtime-managed types, the closure ABI, and the tier ladder.