Processos e channels
Objetivo: criar processos com
spawn, fazer eles conversarem por channels tipados, e esperar vários ao mesmo tempo com omatchsem sujeito (o “select”).
Processos
Seção intitulada “Processos”A unidade de concorrência é o processo: isolado (heap próprio), barato, gerenciado pelo runtime.
Cria-se com spawn (como o go do Go):
spawn log_metric(x) // fire-and-forget: sem custo, sem referênciaspawn worker(data) catch |e| { ... } // com handler de falha (a morte vira o |e|; ver cap. 07)Processos não compartilham memória (não existe @shared). Eles conversam por channel.
Channels tipados
Seção intitulada “Channels tipados”O channel é tipado pela perspectiva de quem segura o handle: <-T = “eu envio T”, ->T = “eu
recebo T”. Isso elimina a inversão de tipos na assinatura do outro lado:
c: Channel[<-int, ->string] // eu envio int, recebo string
spawn worker(c) // o compilador checa que os dois lados são complementares
fn worker(c: Channel[<-string, ->int]) { // o worker: envia string, recebe int val := -> c // receive (bloqueia até chegar) c <- val.to_string() // send (async, fire-and-forget)}Operadores: chan <- data (send), data := -> chan (receive), e o sync request-reply com
timeout obrigatório:
reply := server <-> req timeout(5s) catch |e| { return e } // Timeout | ProcessDownO timeout é obrigatório no <-> porque dois processos fazendo <-> um no outro dariam deadlock
garantido: o prazo é a saída estrutural. E note que não há coloring: o <-> só suspende o
processo atual; o scheduler cuida do resto.
Esperar vários: match sem sujeito (select)
Seção intitulada “Esperar vários: match sem sujeito (select)”O mesmo match, sem valor entre match e {, espera o primeiro channel pronto:
match { msg := -> chan_a => handle_a(msg) msg := -> chan_b => handle_b(msg)} timeout(100ms) { deu_timeout() // 'timeout' é trailer do select; timeout(0) = poll}Paralelismo de IO é por processos
Seção intitulada “Paralelismo de IO é por processos”Sem Future/await: para N operações em paralelo, você spawna N processos e recebe os resultados:
spawn fetch("https://a", chan_a)spawn fetch("https://b", chan_b)ra := -> chan_a // bloqueia só quando necessáriorb := -> chan_bReferenciar um processo (opt-in)
Seção intitulada “Referenciar um processo (opt-in)”spawn é fire-and-forget e não retorna nada. Para inspecionar um processo depois, registre-o
por nome (estável através de restart): não há pid cru.
@register("db_writer")spawn db_writer(conn)
p := runtime.process("db_writer") // Optional[Process], por nomeme := runtime.self() // a própria referência, de dentro de qualquer processoPróximo: 07 · Resiliência