Saltar al contenido

Reactor de I/O (std::io_runtime)

En esta página

std::io_runtime da acceso al reactor de I/O de Zolo — el mismo bucle de eventos que sirve conexiones TCP, lecturas de archivo asíncronas y otros I/O. En Linux >= 5.19 usa io_uring; en macOS, Windows y kernels más antiguos cae en el backend fallback(thread-park). Como depende del runtime del host, no se puede ejecutar en el sandbox WASM; usa la CLI de Zolo.

Para una pausa simple sin otros I/O en vuelo, process.sleep(ms) es más directo. Usa io_runtime cuando el programa ya está conduciendo el reactor y quieres que el timer conviva con los demás I/O en el mismo bucle.


Timer de una vez: sleep_ms

io_runtime.sleep_ms(ms) programa un timer de disparo único y bloquea hasta que dispara, cediendo el control al reactor (sin busy spin). io_runtime.backend() informa qué implementación fue seleccionada en tiempo de ejecución:

Verifica el backend y mide el tiempo de un sleep_ms(100) con os.clock.

01-sleep.zolo
Playground
// Feature: io_runtime.sleep_ms — reactor-backed timer

// Syntax: io_runtime.sleep_ms(ms: int)

// When to use: when the program is already driving the zolo-io reactor

// (TCP server, file IO, other timers) and you want the same loop turn

// to deliver this sleep alongside whatever else is in flight. For a

// pure pause with no other IO, `process.sleep` / `scheduler.sleep`

// (which use OS thread::sleep) are simpler.


use std::io_runtime
use std::os

// Confirm which backend the runtime resolved to. On Linux ≥ 5.19 you

// see "zolo-io/uring(multishot-accept+timerfd+eventfd)"; on macOS,

// Windows, and older Linux kernels you see "zolo-io/fallback(thread-park)".

print("backend: {io_runtime.backend()}")

// Schedule a one-shot timer for 100ms and block until it fires. The

// reactor handles the actual wait via timerfd (Linux) or condvar

// (fallback) — this Lua-side loop is not a busy spin.

let start = os.clock()
io_runtime.sleep_ms(100)
let elapsed_ms = (os.clock() - start) * 1000.0

print("elapsed: {elapsed_ms}ms")  // expected: ~100 (±10ms wakeup overhead)

Requiere la CLI o el host de Zolo; ábrelo en el playground o ejecútalo localmente.


Timers periódicos: every_ms, wait_next y cancel

io_runtime.every_ms(interval, tag) arma un timer recurrente identificado por una etiqueta numérica. io_runtime.wait_next() bloquea mediante el reactor y devuelve el próximo evento { kind, user_data }. Múltiples timers comparten el mismo bucle; los disparos que llegan juntos se encolan para no perderse. Cancela siempre con io_runtime.cancel(handle) al salir del ámbito:

Dos timers concurrentes (50 ms y 150 ms); recolecta 6 eventos y cancela ambos.

02-every-and-cancel.zolo
Playground
// Feature: io_runtime.every_ms + wait_next + cancel — recurring timers

// When to use: build a simple event loop with multiple periodic timers

// (heartbeat, metrics flush, watchdog) without spawning OS threads.

// The reactor batches all fires into one `io_uring_enter` syscall on

// Linux; the fallback uses a condvar park.


use std::io_runtime

// Two concurrent timers — distinguish via the optional `tag` arg which

// is echoed in each event's `user_data` field.

let fast = io_runtime.every_ms(50, 1)
let slow = io_runtime.every_ms(150, 2)

var fires = 0
var fast_count = 0
var slow_count = 0

// Pull events one at a time. wait_next() blocks via the reactor, so

// the loop is not a busy spin. Events that arrive in the same kernel

// batch are queued internally and handed back on successive calls so

// concurrent timer fires never silently disappear.

while fires < 6 {
  let ev = io_runtime.wait_next()
  if ev.kind == "timer" {
    if ev.user_data == 1 {
      fast_count += 1
    }
    if ev.user_data == 2 {
      slow_count += 1
    }
  }
  fires += 1
}

// Always cancel timers before leaving the scope — the reactor would

// keep them armed otherwise. Idempotent / safe to call twice.

io_runtime.cancel(fast)
io_runtime.cancel(slow)

print("fast fires: {fast_count}")  // expected: ~5 (50ms × 5 < 300ms)

print("slow fires: {slow_count}")  // expected: ~1-2 (150ms × 2 ≈ 300ms)

print("total events: {fires}")     // expected: 6

Requiere la CLI o el host de Zolo; ábrelo en el playground o ejecútalo localmente.

Desafío

Agrega un tercer timer de 200 ms con etiqueta 3 y ajusta el bucle para recolectar 10 eventos. ¿Cuántos disparos del timer lento esperas?

Consulta también

Buscar en Zolo

9 resultados

enespt-br