Pular para o conteúdo

Channels e Corrotinas

Channels estilo Go para comunicação entre corrotinas. Crie channels com ou sem buffer, envie e receba valores, e coordene entre processos concorrentes usando instruções select.

O global channel está sempre disponível.

Channels sem buffer (tamanho 0) requerem que remetente e receptor estejam prontos antes da transferência completar. Channels com buffer permitem que envios completem imediatamente enquanto houver espaço disponível:

-- Sem buffer: sincroniza remetente e receptor
local sync_ch = channel.new()
-- Com buffer: enfileirar até 10 mensagens
local work_queue = channel.new(10)
ParâmetroTipoDescrição
sizeintegerCapacidade do buffer (padrão: 0 para sem buffer)

Retorna: channel

Enviar um valor para o channel. Bloqueia até um receptor estar pronto (sem buffer) ou espaço no buffer estar disponível (com buffer):

-- Enviar trabalho para pool de workers
local jobs = channel.new(100)
for i, task in ipairs(tasks) do
jobs:send(task) -- Bloqueia se buffer cheio
end
jobs:close() -- Sinalizar que não há mais trabalho
ParâmetroTipoDescrição
valueanyValor a enviar

Retorna: boolean

Lança erro se channel estiver fechado.

Receber um valor do channel. Bloqueia até um valor estar disponível ou o channel estar fechado:

-- Worker consumindo da fila de jobs
while true do
local job, ok = work:receive()
if not ok then
break -- Channel fechado, não há mais trabalho
end
process(job)
end

Retorna: any, boolean

  • value, true - Recebeu um valor
  • nil, false - Channel fechado e vazio

Fechar o channel. Remetentes pendentes recebem erro, receptores pendentes recebem nil, false. Lança erro se já estiver fechado:

local results = channel.new(10)
-- Produtor preenche resultados
for _, item in ipairs(data) do
results:send(process(item))
end
results:close() -- Sinalizar conclusão

Aguardar múltiplas operações de channel simultaneamente. Essencial para tratar múltiplas fontes de eventos, implementar timeouts e construir sistemas responsivos:

local result = channel.select(cases)
ParâmetroTipoDescrição
casestableArray de casos select
defaultbooleanSe true, retorna imediatamente quando nenhum caso está pronto

Retorna: table com campos: channel, value, ok, default

Aguardar resultado com timeout usando time.after().

local time = require("time")
local result_ch = worker:response()
local timeout = time.after("5s")
local r = channel.select {
result_ch:case_receive(),
timeout:case_receive()
}
if r.channel == timeout then
return nil, errors.new("TIMEOUT", "Operation timed out")
end
return r.value

Mesclar múltiplas fontes em um handler.

local events = process.events()
local inbox = process.inbox()
local shutdown = channel.new()
while true do
local r = channel.select {
events:case_receive(),
inbox:case_receive(),
shutdown:case_receive()
}
if r.channel == shutdown then
break
elseif r.channel == events then
handle_event(r.value)
else
handle_message(r.value)
end
end

Verificar se dados estão disponíveis sem bloquear.

local r = channel.select {
ch:case_receive(),
default = true
}
if r.default then
-- Nada disponível, fazer outra coisa
else
process(r.value)
end

Criar casos para uso com channel.select:

-- Caso send - completa quando channel pode aceitar valor
ch:case_send(value)
-- Caso receive - completa quando valor disponível
ch:case_receive()
local work = channel.new(100)
local results = channel.new(100)
-- Criar workers
for i = 1, num_workers do
process.spawn("app.workers:processor", "app:processes", work, results)
end
-- Alimentar trabalho
for _, item in ipairs(items) do
work:send(item)
end
work:close()
-- Coletar resultados
local processed = {}
while #processed < #items do
local result, ok = results:receive()
if not ok then break end
table.insert(processed, result)
end
CondiçãoTipoRetentável
Send em channel fechadoerro runtimenão
Close de channel fechadoerro runtimenão
Caso inválido em selecterro runtimenão