← index

Worker

inherits Object

An isolate: a fresh VM on its own OS thread (or child process) with message lanes to its parent. Parent side: Worker.spawn:'unit.qn' answers a handle -- send: / receive exchange values, join parks until the unit finishes. Worker side, inside the spawned unit: class-side Worker.receive / Worker.send: are the mirror lanes, and Worker.worker? says which side you are on. Messages deep-copy plain data (numbers, strings, booleans, nil, Bytes, Lists, Maps); symbols, instances, and resources refuse -- and blocks cross only as a whole thread-backed message. See docs/internal/CONCURRENCY_ARCH.md.

var w = Worker.spawn:'jobs/indexer.qn';
w.send:#( 'index' 'docs/' );
var answer = w.receive;
w.join

Class methods

receive

Worker side (inside a spawned unit): park for the next value from the parent; nil once the parent's lane is closed and drained. Raises when not inside a worker.

native

send:

Worker side (inside a spawned unit): send a value to the parent's receive lane (deep-copied). Raises when not inside a worker, or when the parent has gone away. Answers nil.

native

spawn:

Boot a fresh VM running the unit at the String path on its own OS thread and answer its handle immediately. The unit runs to completion; join observes it. Worker.spawn:(VM.unit) runs another copy of the current program.

native

spawn: backing:

As spawn:, choosing the backing at spawn time: 'thread' (the default) or 'process' -- a child qn process bridged over the extension wire, whose messages carry data only (blocks cannot cross a process boundary).

native

start:

Spawn a thread-backed worker from a portable BLOCK instead of a unit file: the block's template ships by reference plus a deep-copied snapshot of its free reads, and join answers the block's value (unlike a unit worker's nil). The portability scan refuses write-captures, ^^, self/@fields, guarded blocks, and class/method definition -- loudly, at submit time. The block takes no parameters; send it data through the lanes.

var h = Worker.start:{ 21 * 2 };
h.join    "* -> 42

native

start: backing:

As start: for 'thread' backing. Blocks cannot cross a process boundary (templates are in-process references), so 'process' refuses loudly -- put the code in a unit and Worker.spawn:backing: it instead.

native

worker?

True inside a spawned worker, false in the main program -- how a unit that can run both ways tells which side it is on.

native

Instance methods

join

Park until the worker finishes. A Worker.start: block worker answers the block's value (copied); a unit worker answers nil. Raises the worker's error, catchably, if it failed. A handle can be joined once -- a second join raises.

native

label:

Restamp the worker's row in VM.ps / VM.psTree with a human-readable name; answers the handle. The Plan layer marks ownership and orphans this way.

native

receive

Park until the worker sends a value back (its class-side Worker.send:); nil once the worker has exited and its outbox is drained. Parks like any I/O wait, so it composes with Async.gather: / timeout:do: / cancellation.

native

send:

Send a value into the worker's inbox (deep-copied; a thread-backed worker also accepts a portable block). Raises if the worker has exited. Answers nil.

native

terminate

Kill a process-backed worker -- REAL cancellation, idempotent; a later join reports the exit as an error. A thread-backed worker cannot be killed: this raises, so orphan or join it instead.

native