0Pricing
Lua Academy · Lektion

Producer-Consumer-Muster

Implementieren Sie mit Coroutinen eine Producer-Consumer-Pipeline

Producer-Consumer-Muster ist eine kostenlose Lua Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Lua Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Lua Academy-Kurs umfasst insgesamt 4 Lektionen.

Das Muster erklärt

Das Produzent-Konsument-Muster mit Coroutines: Der Produzent erzeugt Daten und gibt jedes Element über yield zurück; der Konsument empfängt die Elemente einzeln. Keiner muss die Implementierung des anderen kennen – die Kommunikation erfolgt über yield/resume. Dadurch werden Datenerzeugung und Datenverarbeitung voneinander entkoppelt.

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

Unendlicher Produzent

Eine Produzenten-Coroutine kann eine unendliche Sequenz zurückgeben. Der Konsument bestimmt, wann angehalten wird. Das eignet sich hervorragend für Datenquellen mit Streaming: Messwerte von Sensoren, Log-Ereignisse oder generierte Sequenzen.

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

Der Konsument als Coroutine

Auch der Konsument kann eine Coroutine sein, wodurch ein vollständig symmetrisches Produzent-Konsument-Paar entsteht. Eine dritte Funktion, der „Treiber“, koordiniert beide. Das ist nützlich für gepufferte Pipelines, in denen Produzent und Konsument mit unterschiedlichen Geschwindigkeiten arbeiten.

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

Backpressure

Backpressure bedeutet, dass der Konsument dem Produzenten signalisiert, langsamer zu werden. Bei Coroutines geschieht dies ganz natürlich: Der Produzent ruft nach jedem Element yield auf und wartet, bis der Konsument das nächste anfordert. Wenn der Konsument langsam ist, wartet der Produzent einfach.

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

Batch-Verarbeitung

Ein Produzent für Batch-Verarbeitung sammelt N Elemente, bevor er einen Batch zurückgibt. Der Konsument empfängt vollständige Batches und verarbeitet sie. Dadurch wird der Koordinationsaufwand bei Produzenten mit hoher Frequenz reduziert.

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

Produzent für Dateizeilen

Lesen Sie eine Datei verzögert: Eine Produzenten-Coroutine liest die Zeilen einzeln und gibt jede über yield zurück. Der Konsument verarbeitet die Zeilen, ohne die gesamte Datei in den Speicher laden zu müssen.

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)

Transformationsstufe

Fügen Sie zwischen Produzent und Konsument eine Transformationsstufe ein. Die Transformation liest aus einer Coroutine und gibt verarbeitete Werte an eine andere zurück. Erstellen Sie Daten-Pipelines, indem Sie solche Stufen verketten.

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

Fehlerweitergabe in Pipelines

Fehler in Coroutine-Pipelines werden über den Zustand dead oder über pcall weitergegeben. Umschließen Sie Pipeline-Stufen mit pcall, um Fehler abzufangen und angemessen zu behandeln, ohne die gesamte Pipeline zum Absturz zu bringen.

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

Produzenten zusammenführen

Fassen Sie mehrere Produzenten zu einem zusammen: Wechseln Sie im Round-Robin-Verfahren zwischen allen aktiven Produzenten und geben Sie nacheinander jeweils ein Element zurück. Beenden Sie den Vorgang, wenn alle Produzenten erschöpft sind.

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

Praxisbeispiel

Pipeline zur Log-Verarbeitung: Der Produzent liest Log-Zeilen, die Filterstufe behält nur Fehlerzeilen, die Transformationsstufe extrahiert wichtige Informationen und der Konsument gruppiert nach Fehlertyp. Jede Stufe ist eine unabhängige und testbare Coroutine.

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

Schnelltest

Wie verarbeitet das Produzent-Konsument-Muster mit Coroutines Backpressure?

Rückblick: Produzent und Konsument

Zusammenfassung:

  • Der Produzent gibt Elemente über yield zurück; der Konsument steuert ihn durch Aufrufe von resume
  • Unendliche Produzenten: while true do yield() end
  • Pipelines: Verketten Sie Transformations-Coroutines zwischen Produzent und Konsument
  • Backpressure erfolgt automatisch: Der Produzent wartet auf den Konsumenten
  • Batch-, Filter- und Zusammenführungsstufen als Coroutine-Wrapper
  • Verwenden Sie pcall in Pipeline-Stufen zur Isolierung von Fehlern

Häufig gestellte Fragen

Ist die Lektion „Producer-Consumer-Muster“ kostenlos?

Ja — der vollständige Text von „Producer-Consumer-Muster“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Lua Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Lua Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Producer-Consumer-Muster“?

Implementieren Sie mit Coroutinen eine Producer-Consumer-Pipeline Du übst Lua Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Lua Academy zu starten?

Keine Vorkenntnisse erforderlich. Lua Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.

Wie lange dauert die Lektion „Producer-Consumer-Muster“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Lua Academy-Lektion Code schreiben und ausführen?

Ja. Jede Lua Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Coroutinen erstellen
  2. resume und yield
  3. Coroutine-Status
  4. Producer-Consumer-Muster
← Zurück zu Lua Academy