Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

isolate.channel

import isolate.channel

isolate lifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelled isolate.channel.* needs import isolate.channel.

Thread-safe, multi-producer multi-consumer (MPMC) communication queues for passing values and messages across isolate isolates.

Overview

Channels provide synchronized, data-race-free message passing between concurrent isolate isolates. Because Zuri isolates execute within isolated heaps, sending a value over a Channel deep-copies the object graph across the boundary barrier, preserving internal references and graph topologies without sharing mutable memory.

Channel handles are re-exported by the isolate module, making them accessible directly via isolate.Channel or isolate.channel().

Channel Types & Backpressure

  • Unbounded Channels (capacity: 0 or nil): Messages are enqueued without blocking send(). The queue dynamically grows as needed. - Bounded Channels (capacity: n > 0): The channel holds at most n unread messages. Calling send() when the queue is full blocks the sending isolate until a consumer calls recv(), providing automatic backpressure to prevent producer tasks from exhausting system memory.

Channel Lifecycle

  • Sending: Channel.send(val, timeout) pushes a value into the channel. If the channel is bounded and full, the call blocks until capacity is available or timeout elapses. - Receiving: Channel.recv(timeout) blocks until a value arrives. If the channel is closed and all queued items have been drained, recv() returns nil. - Non-blocking Peek: Channel.try_recv() retrieves the next value immediately without blocking, returning nil if the channel is currently empty. - Closing: Channel.close() shuts down the channel for subsequent sends. Messages already in the queue remain readable until drained. Subsequent calls to send() on a closed channel raise a IsolateError.

Multiplexing with select()

The select() function allows an isolate to wait on multiple channels simultaneously. It blocks until at least one channel is ready to deliver a value (or is closed), returning a pair [ready_channel, value].

Examples

1. Producer-Consumer Pipeline

import isolate

var ch = isolate.channel(10)  # bounded channel with capacity 10

def producer(out_ch) {
  iter var i = 1; i <= 5; i++ {
    out_ch.send("item-${i}")
  }
  out_ch.close()
}

var producer_task = isolate.spawn(producer, ch)

while true {
  var msg = ch.recv()
  if msg == nil {
    break  # the channel is closed and empty
  }

  echo "Received: ${msg}"
}

producer_task.join()

2. Fan-Out / Fan-In Isolate Pool

import isolate

var results = isolate.channel()

def isolate_job(isolate_id, count, out_ch) {
  iter var i = 1; i <= count; i++ {
    out_ch.send("isolate-${isolate_id}-result-${i}")
  }
}

var w1 = isolate.spawn(isolate_job, 1, 3, results)
var w2 = isolate.spawn(isolate_job, 2, 3, results)

iter var i = 0; i < 6; i++ {
  echo results.recv()
}

w1.join()
w2.join()

3. Multiplexing Channels with select()

import isolate

var ch1 = isolate.channel()
var ch2 = isolate.channel()

isolate.spawn(@(c) { c.send("from ch1") }, ch1)
isolate.spawn(@(c) { c.send("from ch2") }, ch2)

iter var i = 0; i < 2; i++ {
  var result = isolate.select([ch1, ch2], 1.0)
  var ready_ch = result[0]
  var value = result[1]
  echo "Got: ${value}"
}

Functions

channel()

isolate.channel(capacity: ?int) -> Channel

Creates a new thread-safe Channel.

import isolate
var unbounded = isolate.channel()
var bounded = isolate.channel(50)

Parameters

  • capacity (?int) — Maximum buffered messages. nil or 0 means unbounded.

Returns Channel

select()

isolate.select(channels: list, timeout: ?number)

Multiplexes across multiple channels, blocking until at least one channel is ready to deliver a value or is closed.

The ready value is consumed from the selected channel exactly as if recv() were called on it directly.

If multiple channels are ready simultaneously, ties are resolved in favor of the channel with the lower index in channels.

import isolate
var ch1 = isolate.channel()
var ch2 = isolate.channel()

var res = isolate.select([ch1, ch2], 1.5)
var active_ch = res[0]
var msg = res[1]
echo "Received ${msg} from channel"

Parameters

  • channels (list) — A non-empty list of Channel instances.
  • timeout (?number) — Maximum seconds to wait before timing out. Waits indefinitely if omitted or nil.

Returns — list: A two-element list [ready_channel, value], where value is the message received (nil if the channel was closed and drained).

Raises ValueError if channels is empty.

Raises IsolateTimeoutError if timeout seconds elapse before any channel is ready.

Raises IsolateCancelledError if the calling isolate is cancelled while blocked.

Classes

Channel

class isolate.Channel

A thread-safe, multi-producer multi-consumer (MPMC) message queue.

Constructor

isolate.Channel(capacity: ?int)

Constructs a new Channel with the specified capacity limit.

import isolate
var unbounded = isolate.channel()
var bounded = isolate.channel(100)

Parameters

  • capacity (?int) — Maximum number of buffered items before send() blocks for backpressure. nil or 0 creates an unbounded channel.

Raises ValueError if capacity is negative.

Channel.send()

isolate.Channel.send(value, timeout: ?number)

Sends value into the channel.

If the channel is bounded and currently full, this call blocks the calling isolate until space becomes available, the timeout elapses, or the caller is cancelled.

ch.send("data payload")
ch.send(42, 0.5)  # wait at most 500ms

Parameters

  • value (any) — The value or object graph to send.
  • timeout (?number) — Maximum seconds to wait before timing out. Waits indefinitely if omitted or nil.

Raises IsolateError if the channel has been closed.

Raises IsolateTimeoutError if timeout seconds elapse before space is available.

Raises IsolateCancelledError if the calling isolate is cancelled while blocked.

Channel.recv()

isolate.Channel.recv(timeout: ?number)

Blocks until a message is available and retrieves it.

If the channel is closed and all buffered messages have been received, recv() returns nil.

var item = ch.recv()
var timed_item = ch.recv(2.0)

Parameters

  • timeout (?number) — Maximum seconds to wait for a message. Waits indefinitely if omitted or nil.

Returns — any: The received value, or nil if the channel is closed and empty.

Raises IsolateTimeoutError if timeout seconds elapse before a value is received.

Raises IsolateCancelledError if the calling isolate is cancelled while blocked.

Channel.try_recv()

isolate.Channel.try_recv()

Attempts to receive a value without blocking.

var item = ch.try_recv()
if item != nil {
  echo "Processed: ${item}"
}

Returns — any: The next available message, or nil if the channel is currently empty or closed.

Channel.close()

isolate.Channel.close()

Closes the channel.

Buffered messages remain available for consumers to read via recv() or try_recv(). Calling send() after closing raises IsolateError.

ch.close()

Channel.is_closed()

isolate.Channel.is_closed()

Checks whether the channel has been closed.

if !ch.is_closed() {
  ch.send("active")
}

Returns — bool: true if the channel is closed, false otherwise.

Channel.length()

isolate.Channel.length()

Returns the current number of buffered, unread messages in the channel.

var pending = ch.length()

Returns — int: Number of queued items.

Channel.handle()

isolate.Channel.handle()

Returns the underlying native channel pointer.

Used internally by select(). Not intended for direct application usage.


2026, Richard Ore and Zuri contributors