0Pricing
Lua Academy · Lección

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 29

El 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)
end

Contrapresió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: 10

Productor 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 12

Propagació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) end

Combinar 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 6

Caso 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 failed

Comprobació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

  1. Creación de coroutines
  2. resume y yield
  3. Estado de las coroutines
  4. Patrón productor-consumidor
← Volver a Lua Academy