Lua Academy · Les

Producer-consumerpatroon

Implementeer een producer-consumer-pijplijn met coroutines

Les 4 van 412 stappen

Producer-consumerpatroon is een gratis Lua Academy-les op CoddyKit. Dit is les 4 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Lua Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Lua Academy bevat in totaal 4 lessen.

Het patroon uitgelegd

Het producent-consumentpatroon met coroutines: de producent genereert gegevens en levert elk item op; de consument ontvangt de items één voor één. Geen van beide hoeft de implementatie van de ander te kennen — ze communiceren via yield/resume. Hierdoor worden het genereren en verwerken van gegevens van elkaar losgekoppeld.

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}))

Oneindige producent

Een producent-coroutine kan een oneindige reeks opleveren. De consument bepaalt wanneer hij stopt. Dit is ideaal voor gegevensbronnen die gegevens streamen, zoals sensormetingen, loggebeurtenissen en gegenereerde reeksen.

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

Consument als coroutine

De consument kan ook een coroutine zijn, waardoor een volledig symmetrisch producent-consumentpaar ontstaat. Een derde functie, de "aanstuurfunctie", coördineert beide. Dit is nuttig voor gebufferde pijplijnen waarin producent en consument verschillende snelheden hebben.

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

Terugdruk

Terugdruk ontstaat wanneer de consument de producent laat vertragen. Met coroutines gaat dit vanzelf: de producent voert na elk item yield uit en wacht tot de consument het volgende item opvraagt. Als de consument traag is, wacht de producent gewoon.

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

Verwerking in batches

Een producent die in batches werkt, verzamelt N items voordat hij een batch oplevert. De consument ontvangt en verwerkt volledige batches. Hierdoor neemt de coördinatie-overhead voor producenten met een hoge frequentie af.

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

Producent van bestandsregels

Lees een bestand lui: een producent-coroutine leest de regels één voor één en levert elke regel op. De consument verwerkt de regels zonder het volledige bestand in het geheugen te laden.

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)

Transformatiefase

Voeg een transformatiefase toe tussen producent en consument. De transformatie leest van één coroutine en levert verwerkte waarden aan een andere. Bouw gegevenspijplijnen door deze fasen aan elkaar te koppelen.

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

Foutdoorgifte in pijplijnen

Fouten in coroutinepijplijnen worden doorgegeven via de toestand beëindigd of via pcall. Wikkel pijplijnfasen in pcall om fouten op te vangen en netjes af te handelen zonder de hele pijplijn te laten crashen.

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

Producenten samenvoegen

Combineer meerdere producenten tot één producent: ga in een round-robinpatroon langs alle actieve producenten en lever telkens één item op. Stop wanneer alle producenten zijn uitgeput.

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

Praktijkvoorbeeld

Pijplijn voor logverwerking: de producent leest logregels, de filterfase houdt alleen foutregels over, de transformatiefase haalt belangrijke informatie eruit en de consument groepeert op fouttype. Elke fase is een onafhankelijke coroutine die afzonderlijk kan worden getest.

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

Snelle controle

Hoe handelt het producent-consumentpatroon met coroutines terugdruk af?

Samenvatting: producent-consument

Samenvatting:

  • De producent levert items op; de consument stuurt aan door resume aan te roepen
  • Oneindige producenten: while true do yield() end
  • Pijplijnen: koppel transformatiecoroutines tussen producent en consument
  • Terugdruk gebeurt automatisch: de producent wacht op de consument
  • Gebruik batch-, filter- en samenvoegfasen als coroutinewrappers
  • Gebruik pcall in pijplijnfasen om fouten van elkaar te isoleren
Gratis beginnen

Leer Lua met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
40
Lessen
159

Veelgestelde vragen

Is de les “Producer-consumerpatroon” gratis?

Ja — je kunt hier op het web alle 3 lessen van het leerpad Lua Academy, waaronder “Producer-consumerpatroon”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus Lua Academy bevat in totaal 4 lessen.

Wat leer ik in “Producer-consumerpatroon”?

Implementeer een producer-consumer-pijplijn met coroutines Je oefent met Lua Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met Lua Academy te beginnen?

Ervaring vooraf is niet nodig. Lua Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 4 van 4.

Hoe lang duurt de les “Producer-consumerpatroon”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over Lua Academy?

Ja. Elke les over Lua Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. Coroutines maken
  2. resume en yield
  3. Coroutine-status
  4. Producer-consumerpatroon
← Terug naar Lua Academy