Pular para o conteúdo

Canais

Nesta página

Canais são a forma idiomática de comunicar tarefas em Zolo. channel(N) cria um canal com buffer de capacidade N. ch.send(v) enfileira um valor; ch.recv() retira e bloqueia o chamador enquanto o canal estiver vazio — por isso consumidores sempre precisam rodar dentro de spawn { ... }.

recv retorna um Option: use .is_some() / .unwrap() para inspecionar, ou .unwrap_or(padrão) para fornecer um valor de fallback. Quando o canal fecha e o buffer está vazio, recv devolve nil (opção vazia).

Canal de rendezvous (channel(0)) com dois spawns: produtor fecha, consumidor verifica is_some e is_none.

09-channels-basic.zolo
Playground
// Feature: channels — typed CSP-style message passing

// Syntax: `channel(buffer_size)` creates one. `ch.send(v)` enqueues,

// `ch.recv()` dequeues. `recv` returns an `Option` — use `is_some` /

// `unwrap` (or `for x in ch { ... }` which strips Option for you).

// `recv` blocks the caller, so it must run inside a coroutine.

// When to use: producer/consumer pipelines, bounded queues, fan-out

// of work across spawned tasks.


let ch = channel(0)
scope {
    spawn {
        ch.send(10)
        ch.send(20)
        ch.close()
    }
    spawn {
        let a = ch.recv()
        let b = ch.recv()
        let c = ch.recv()
        print(a.is_some())   // expected: true

        print(a.unwrap())    // expected: 10

        print(b.is_some())   // expected: true

        print(b.unwrap())    // expected: 20

        print(c.is_none())   // expected: true   (channel closed, drained)

    }
}

O padrão for x in ch { ... } drena o canal até ele fechar, desembrulhando o Option automaticamente. É a forma mais limpa de consumir um stream de mensagens.

Produtor envia três valores e fecha; consumidor usa for x in ch e imprime cada um.

10-channels-for-in.zolo
Playground
// Feature: receive loop — `for x in ch` until close

// Syntax: `for x in ch { ... }` calls recv internally and exits when

// the channel is closed. The body runs once per received value.

// When to use: streaming consumers, log readers, event drainers —

// anywhere "process every message until the producer stops".


let ch = channel(0)
scope {
  spawn {
    ch.send(1)
    ch.send(2)
    ch.send(3)
    ch.close()
  }

  spawn {
    for x in ch {
      print(x)
    }
  }
}

print("done")
// expected:

//   1

//   2

//   3

//   done

channel(N) com N >= 1 bufferiza até N valores antes de aplicar contrapressão: o produtor bloqueia no send enquanto o buffer estiver cheio. Isso nivela rajadas sem crescimento ilimitado de memória.

Buffer de tamanho 2: o terceiro send espera até o consumidor liberar um slot.

11-channels-bounded.zolo
Playground
// Feature: bounded channels — backpressure built in

// Syntax: `channel(N)` reserves a buffer of size N. Sends past

// capacity yield until the consumer drains a slot.

// When to use: rate-limit producers, prevent memory blowups in

// pipelines, smooth bursty workloads with a fixed-size queue.


let ch = channel(2)
scope {
    spawn {
        ch.send("a")
        ch.send("b")
        // The buffer is full; this third send waits until the consumer

        // recvs at least once.

        ch.send("c")
        ch.close()
    }
    spawn {
        print(ch.recv().unwrap())     // expected: a

        print(ch.recv().unwrap())     // expected: b

        print(ch.recv().unwrap())     // expected: c

        print(ch.recv().is_none())    // expected: true

    }
}

Desafio

Modifique o exemplo básico para usar channel(4) em vez de channel(0) e observe como o produtor avança sem esperar o consumidor.

Buscar no Zolo

9 resultados

enespt-br