Channels e Concorrência
Channels e Concorrência
Seção intitulada “Channels e Concorrência”Channels estilo Go para programação concorrente dentro de processos.
Criando Channels
Seção intitulada “Criando Channels”Channels são canais de comunicação para corrotinas. Crie com channel.new(capacity):
local ch = channel.new(1) -- channel com buffer, capacidade 1Channels com Buffer
Seção intitulada “Channels com Buffer”Channels com buffer permitem envios sem bloquear até que o buffer esteja cheio:
local ch = channel.new(3) -- buffer comporta 3 itens
-- Enviar sem bloquearch:send(1)ch:send(2)ch:send(3)
-- Receber em ordem FIFOlocal v1, ok1 = ch:receive() -- 1, truelocal v2, ok2 = ch:receive() -- 2, truelocal v3, ok3 = ch:receive() -- 3, trueChannels sem Buffer
Seção intitulada “Channels sem Buffer”Channels sem buffer (capacidade 0) sincronizam remetente e receptor:
local ch = channel.new(0) -- sem bufferlocal done = channel.new(1)
coroutine.spawn(function() ch:send("from spawn") -- bloqueia até receptor estar pronto done:send(true)end)
local val = ch:receive() -- recebe "from spawn"local completed = done:receive()Channel Select
Seção intitulada “Channel Select”channel.select aguarda múltiplos channels, retorna a primeira operação pronta:
local ch1 = channel.new(1)local ch2 = channel.new(1)
ch1:send("ch1_value")
local result = channel.select{ ch1:case_receive(), ch2:case_receive()}
-- result é uma tabela com: channel, value, okresult.channel == ch1 -- trueresult.value -- "ch1_value"result.ok -- trueSelect com Send
Seção intitulada “Select com Send”Use case_send para tentar envios não-bloqueantes:
local ch = channel.new(1)
local result = channel.select{ ch:case_send("sent")}
result.ok -- true (envio bem-sucedido)
local v = ch:receive() -- "sent"Padrão Produtor-Consumidor
Seção intitulada “Padrão Produtor-Consumidor”Produtor único, consumidor único:
local ch = channel.new(5)local done = channel.new(1)local consumed = 0
-- Consumidorcoroutine.spawn(function() while true do local v, ok = ch:receive() if not ok then break end consumed = consumed + 1 end done:send(consumed)end)
-- Produtorfor i = 1, 10 do ch:send(i)endch:close()
local total = done:receive() -- 10Padrão Ping-Pong
Seção intitulada “Padrão Ping-Pong”Sincronizar duas corrotinas:
local ping = channel.new(0)local pong = channel.new(0)local rounds_done = channel.new(1)
coroutine.spawn(function() for i = 1, 5 do ping:receive() pong:send("pong") end rounds_done:send(true)end)
for i = 1, 5 do ping:send("ping") pong:receive()end
local completed = rounds_done:receive()Padrão Fan-Out
Seção intitulada “Padrão Fan-Out”Um produtor, múltiplos consumidores:
local work = channel.new(10)local results = channel.new(10)
-- Criar 3 workersfor w = 1, 3 do coroutine.spawn(function() while true do local job, ok = work:receive() if not ok then break end results:send(job * 2) end end)end
-- Enviar trabalhofor i = 1, 6 do work:send(i)endwork:close()
-- Coletar resultadoslocal sum = 0for i = 1, 6 do local r = results:receive() sum = sum + rend-- sum = (1+2+3+4+5+6)*2 = 42Padrão Fan-In
Seção intitulada “Padrão Fan-In”Múltiplos produtores, consumidor único:
local output = channel.new(10)local producer_count = 4local items_per_producer = 5
-- Criar produtoresfor p = 1, producer_count do coroutine.spawn(function() for i = 1, items_per_producer do output:send({producer = p, item = i}) end end)end
-- Coletar todas as mensagenslocal received = {}for i = 1, producer_count * items_per_producer do local msg = output:receive() table.insert(received, msg)end
-- Verificar que todos os produtores enviaram seus itenslocal counts = {}for _, msg in ipairs(received) do counts[msg.producer] = (counts[msg.producer] or 0) + 1endFechando Channels
Seção intitulada “Fechando Channels”Feche channels para sinalizar conclusão. Receptores recebem ok = false quando o channel está fechado e vazio:
local ch = channel.new(5)local done = channel.new(1)
coroutine.spawn(function() local count = 0 while true do local v, ok = ch:receive() if not ok then break end -- channel fechado count = count + 1 end done:send(count)end)
for i = 1, 10 do ch:send(i)endch:close() -- sinalizar que não há mais valores
local total = done:receive()Métodos de Channel
Seção intitulada “Métodos de Channel”Operações disponíveis:
channel.new(capacity)- Criar channel com tamanho de bufferch:send(value)- Enviar valor (bloqueia se buffer cheio)ch:receive()- Receber valor, retornavalue, okch:close()- Fechar channelch:case_send(value)- Criar caso de envio para selectch:case_receive()- Criar caso de recepção para selectchannel.select{cases...}- Aguardar múltiplas operações
Próximos Passos
Seção intitulada “Próximos Passos”- Channel Module Reference - Documentação completa da API
- Processes - Comunicação inter-processo