Concurrency Guide
xxc Concurrency Guide
> Requires the --features concurrency build (all official binaries ship
> with it). The interpreter and compiled binaries carry the same
> worker-pool runtime with identical semantics. Related pages:
> Language Guide ·
> Quick Start ·
> 中文版:并发编程指南。
Concurrency
*(Requires --features concurrency. Available in the interpreter AND in
compiled binaries — compiled programs carry the same worker-pool runtime.)*
spawn starts a task that runs in parallel on the runtime's worker
threads (XXC_CONC_WORKERS, default derived from the CPU count). Tasks are
cheap (each is a coroutine with its own stack) — spawn thousands.
ch := chan(4) // buffered channel (capacity 4)
spawn {
ch <- compute() // send
}
v := <-ch // receive (blocks until available)
chan()creates an unbuffered (rendezvous) channel;chan(n)a
buffered one.
- Sends block while full; receives block while empty; both park the task
(other tasks keep running).
- A value sent on an unbuffered channel transfers directly to a waiting
receiver.
select
select {
case x := <-ch1 { print("ch1:", x) }
case ch2 <- 42 { print("sent") }
default { print("nothing ready") } // optional: non-blocking
}
select commits to whichever operation is ready; with default it never
blocks. Channels and send-values are evaluated once, on entry.
Semantics
- main returns → program exits (remaining tasks are dropped), matching Go.
- If every task is blocked with no pending I/O, the runtime reports a
deadlock with source position.
- Tasks may share
classinstances, arrays, and channels;structvalues
are copied between tasks.
// parallel fan-out
results := chan(4)
for i in range(0, 4) {
spawn { results <- fib(31) }
}
sum := 0
for i in range(0, 4) { sum = sum + <-results }
On a 4+ core machine this runs measurably faster than the sequential
equivalent (~2.3× measured for 4 tasks).
Async I/O
*(Requires --features concurrency.)* The modules std/fs, net/tcp, and
net/http perform blocking-looking calls that never stall other tasks:
work is offloaded to an I/O thread pool and the task parks until completion.
import fs "std/fs"
import tcp "net/tcp"
content := fs.read_file("data.txt") // yields; other tasks run
c := tcp.accept(listener) // yields
Line-atomic printing
The parts of a print statement (strings/ints/floats) are appended to a
per-line buffer under a statement-level owner-token lock and flushed as
one write at the newline — on every backend, concurrent tasks can
never tear an output line. The property is verified word-for-word by the
stress multiset gates at w=2 and w=4:
# verification (in the repo): the sorted w=4 line multiset must equal w=1
XXC_CONC_WORKERS=4 ./stress_conc | sort # == the sorted w=1 output
Runtime behavior quick notes
mainreturning exits the program (remaining tasks dropped), matching Go;- if every task is blocked with no pending I/O, the runtime reports a
deadlock with source position;
XXC_CONC_WORKERS=Nselects the worker count (derived from the CPU
count by default);
- tasks share
classinstances, arrays, and channels;structvalues are
copied between tasks.