Patrón productor-consumidor
Implemente una canalización productor-consumidor mediante coroutines.
Patrón productor-consumidor es una lección gratuita de Lua Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Lua Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Lua Academy incluye 4 lecciones en total.
Explicación del patrón
El patrón productor-consumidor con corrutinas: el productor genera datos y produce cada elemento mediante yield; el consumidor recibe los elementos de uno en uno. Ninguno necesita conocer la implementación del otro: se comunican mediante yield/resume. Esto desacopla la generación de datos de su procesamiento.
local function makeProducer(items)
return coroutine.create(function()
for _, item in ipairs(items) do
coroutine.yield(item)
end
end)
end
local function consume(producer)
while true do
local ok, item = coroutine.resume(producer)
if not ok or item == nil then break end
print("Processing:", item)
end
end
consume(makeProducer({10, 20, 30, 40}))Productor infinito
Una corrutina productora puede generar una secuencia infinita mediante yield. El consumidor controla cuándo detenerse. Esto resulta perfecto para fuentes de datos en streaming, como lecturas de sensores, eventos de registros y secuencias generadas.
local function primes()
return coroutine.wrap(function()
local function isPrime(n)
if n<2 then return false end
for i=2, math.floor(math.sqrt(n)) do
if n%i==0 then return false end
end
return true
end
local n = 2
while true do
if isPrime(n) then coroutine.yield(n) end
n = n + 1
end
end)
end
local gen = primes()
for i = 1, 10 do
io.write(gen() .. " ")
end
print() -- 2 3 5 7 11 13 17 19 23 29El consumidor como corrutina
El consumidor también puede ser una corrutina, lo que crea un par productor-consumidor completamente simétrico. Una tercera función «controladora» coordina ambos. Esto resulta útil para pipelines con búferes en los que el productor y el consumidor trabajan a ritmos diferentes.
local function producer()
return coroutine.create(function(consumer)
for i = 1, 5 do
coroutine.resume(consumer, i * 10)
coroutine.yield() -- wait
end
end)
end
local consumer = coroutine.create(function()
while true do
local val = coroutine.yield()
print("Received:", val)
end
end)
coroutine.resume(consumer) -- start, waits for data
local pro = producer()
for i = 1, 5 do
coroutine.resume(pro, consumer)
endContrapresión
La contrapresión se produce cuando el consumidor indica al productor que reduzca el ritmo. Con corrutinas, esto ocurre de forma natural: el productor produce un yield después de cada elemento y espera a que el consumidor solicite el siguiente. Si el consumidor es lento, el productor simplemente espera.
local function slowConsumer(gen)
for v in gen do
-- Simulate slow processing
print("Processing", v, "...")
-- In real code: os.execute("sleep 0.1")
end
end
local function fastProducer(n)
return coroutine.wrap(function()
for i = 1, n do
print("Producing", i)
coroutine.yield(i)
end
end)
end
-- Producer automatically waits for consumer:
slowConsumer(fastProducer(4))Procesamiento por lotes
Un productor por lotes recopila N elementos antes de producir un lote mediante yield. El consumidor recibe y procesa lotes completos. Esto reduce la sobrecarga de coordinación en productores de alta frecuencia.
local function batchProducer(items, batchSize)
return coroutine.wrap(function()
local batch = {}
for _, item in ipairs(items) do
batch[#batch+1] = item
if #batch >= batchSize then
coroutine.yield(batch)
batch = {}
end
end
if #batch > 0 then coroutine.yield(batch) end
end)
end
local data = {1,2,3,4,5,6,7,8,9,10}
for batch in batchProducer(data, 3) do
print("Batch:", table.concat(batch, ","))
end
-- Batch: 1,2,3
-- Batch: 4,5,6
-- Batch: 7,8,9
-- Batch: 10Productor de líneas de archivo
Lea un archivo de forma perezosa: una corrutina productora lee las líneas de una en una y produce cada una mediante yield. El consumidor procesa las líneas sin cargar el archivo completo en memoria.
local function lineProducer(path)
return coroutine.wrap(function()
local f = io.open(path, "r")
if not f then return end
for line in f:lines() do
coroutine.yield(line)
end
f:close()
end)
end
-- Process file line by line without loading all at once
local wordCount = 0
for line in lineProducer("data.txt") do
for _ in line:gmatch("%S+") do
wordCount = wordCount + 1
end
end
print("Words:", wordCount)Etapa de transformación
Inserte una etapa de transformación entre el productor y el consumidor. La transformación lee de una corrutina y produce valores procesados para otra. Cree pipelines de datos encadenando estas etapas.
local function transform(source, fn)
return coroutine.wrap(function()
for v in source do
coroutine.yield(fn(v))
end
end)
end
local numbers = coroutine.wrap(function()
for i = 1, 6 do coroutine.yield(i) end
end)
local doubled = transform(numbers, function(n) return n*2 end)
local filtered = coroutine.wrap(function()
for v in doubled do
if v > 4 then coroutine.yield(v) end
end
end)
for v in filtered do io.write(v.." ") end
print() -- 6 8 10 12Propagación de errores en pipelines
Los errores en los pipelines de corrutinas se propagan mediante el estado de muerto o mediante pcall. Envuelva las etapas del pipeline en pcall para capturar y gestionar los errores correctamente sin bloquear todo el pipeline.
local function safeStage(source, fn)
return coroutine.wrap(function()
for v in source do
local ok, result = pcall(fn, v)
if ok then
coroutine.yield(result)
else
print("Error processing", v, ":", result)
end
end
end)
end
local data = coroutine.wrap(function()
for _, v in ipairs({4, -1, 9, 0, 16}) do coroutine.yield(v) end
end)
local results = safeStage(data, function(n)
assert(n > 0, "non-positive")
return math.sqrt(n)
end)
for v in results do print(v) endCombinar productores
Combine varios productores en uno: distribuya los turnos entre todos los productores activos y produzca cada elemento sucesivamente. Deténgase cuando todos los productores se hayan agotado.
local function merge(...)
local producers = {...}
return coroutine.wrap(function()
while #producers > 0 do
local alive = {}
for _, co in ipairs(producers) do
local ok, v = coroutine.resume(co)
if ok and v ~= nil then
coroutine.yield(v)
alive[#alive+1] = co
end
end
producers = alive
end
end)
end
local function src(items)
return coroutine.create(function()
for _,v in ipairs(items) do coroutine.yield(v) end
end)
end
for v in merge(src({1,3,5}),src({2,4,6})) do
io.write(v.." ")
end
print() -- 1 2 3 4 5 6Caso de uso real
Pipeline de procesamiento de registros: el productor lee las líneas de registro, la etapa de filtrado conserva solo las líneas de error, la etapa de transformación extrae la información clave y el consumidor agrupa por tipo de error. Cada etapa es una corrutina independiente y comprobable.
local function makeFilter(src, pred)
return coroutine.wrap(function()
for line in src do
if pred(line) then coroutine.yield(line) end
end
end)
end
local logs = coroutine.wrap(function()
local entries = {
"INFO: started",
"ERROR: timeout",
"DEBUG: connecting",
"ERROR: auth failed",
}
for _, e in ipairs(entries) do coroutine.yield(e) end
end)
local errors = makeFilter(logs, function(l) return l:match("^ERROR") end)
for line in errors do print(line) end
-- ERROR: timeout
-- ERROR: auth failedComprobación rápida
¿Cómo gestiona la contrapresión el patrón de corrutinas productor-consumidor?
Resumen: productor-consumidor
Resumen:
- El productor produce elementos; el consumidor controla el proceso llamando a resume
- Productores infinitos:
while true do yield() end - Pipelines: encadene corrutinas de transformación entre el productor y el consumidor
- La contrapresión es automática: el productor espera al consumidor
- Use etapas de lotes, filtrado y combinación como envoltorios de corrutinas
- Use pcall en las etapas del pipeline para aislar los errores
Preguntas frecuentes
¿La lección «Patrón productor-consumidor» es gratis?
Sí — el texto completo de «Patrón productor-consumidor» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Lua Academy, actualiza a CoddyKit PRO. El curso de Lua Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Patrón productor-consumidor»?
Implemente una canalización productor-consumidor mediante coroutines. Practicas Lua Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Lua Academy?
No se requiere experiencia previa. Lua Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «Patrón productor-consumidor»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Lua Academy?
Sí. Cada lección de Lua Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Creación de coroutines
- resume y yield
- Estado de las coroutines
- Patrón productor-consumidor