0Pricing
Lua Academy · Pelajaran

Pola Produsen-Konsumen

Implementasikan pipeline produsen-konsumen menggunakan coroutine.

Pola Produsen-Konsumen adalah pelajaran Lua Academy gratis di CoddyKit. Ini adalah pelajaran 4 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Lua Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Lua Academy mencakup 4 pelajaran total.

Penjelasan Pola

Pola produsen-konsumen dengan korutin: produsen menghasilkan data dan melakukan yield pada setiap item; konsumen menerima item satu per satu. Keduanya tidak perlu mengetahui implementasi satu sama lain — keduanya berkomunikasi melalui yield/resume. Dengan demikian, pembuatan data terpisah dari pemrosesan data.

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

Produsen Tak Terbatas

Korutin produsen dapat melakukan yield pada urutan yang tidak terbatas. Konsumen menentukan kapan harus berhenti. Pola ini sangat cocok untuk sumber data streaming: pembacaan sensor, peristiwa log, dan urutan yang dihasilkan.

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

Konsumen sebagai Korutin

Konsumen juga dapat berupa korutin, sehingga terbentuk pasangan produsen-konsumen yang sepenuhnya simetris. Fungsi "penggerak" ketiga mengoordinasikan keduanya. Ini berguna untuk alur dengan penyangga ketika produsen dan konsumen memiliki laju yang berbeda.

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

Tekanan Balik

Tekanan balik terjadi ketika konsumen memberi sinyal kepada produsen untuk memperlambat proses. Dengan korutin, hal ini berlangsung secara alami: produsen melakukan yield setelah setiap item dan menunggu konsumen meminta item berikutnya. Jika konsumen lambat, produsen cukup menunggu.

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

Pemrosesan Secara Kelompok

Produsen berkelompok mengumpulkan N item sebelum melakukan yield pada satu kelompok. Konsumen menerima dan memproses kelompok secara lengkap. Cara ini mengurangi beban koordinasi bagi produsen berfrekuensi tinggi.

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

Produsen Baris Berkas

Baca berkas secara malas: korutin produsen membaca baris satu per satu dan melakukan yield pada setiap baris. Konsumen memproses baris tanpa memuat seluruh berkas ke memori.

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)

Tahap Transformasi

Sisipkan tahap transformasi di antara produsen dan konsumen. Transformasi membaca dari satu korutin dan melakukan yield pada nilai yang telah diproses untuk korutin lain. Bangun alur data dengan merangkai tahap-tahap ini.

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

Penerusan Kesalahan dalam Alur

Kesalahan dalam alur korutin diteruskan melalui keadaan mati atau melalui pcall. Bungkus tahap-tahap alur dalam pcall untuk menangkap dan menangani kesalahan dengan baik tanpa membuat seluruh alur berhenti.

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

Menggabungkan Produsen

Gabungkan beberapa produsen menjadi satu: lakukan pembagian giliran di antara semua produsen yang masih aktif, lalu keluarkan setiap item secara bergantian. Berhenti ketika semua produsen telah kehabisan item.

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

Kasus Penggunaan di Dunia Nyata

Alur pemrosesan log: produsen membaca baris log, tahap penyaring hanya mempertahankan baris kesalahan, tahap transformasi mengambil informasi penting, dan konsumen mengelompokkan berdasarkan jenis kesalahan. Setiap tahap merupakan korutin mandiri yang dapat diuji.

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

Pemeriksaan Singkat

Bagaimana pola korutin produsen-konsumen menangani tekanan balik?

Ringkasan: Produsen-Konsumen

Ringkasan:

  • Produsen melakukan yield pada item; konsumen menggerakkan proses dengan memanggil resume
  • Produsen tak terbatas: while true do yield() end
  • Alur: rangkai korutin transformasi di antara produsen dan konsumen
  • Tekanan balik berlangsung otomatis: produsen menunggu konsumen
  • Gunakan tahap pengelompokan, penyaringan, dan penggabungan sebagai pembungkus korutin
  • Gunakan pcall pada tahap alur untuk mengisolasi kesalahan

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Pola Produsen-Konsumen” gratis?

Ya — teks lengkap “Pola Produsen-Konsumen” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Lua Academy, upgrade ke CoddyKit PRO. Kursus Lua Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Pola Produsen-Konsumen”?

Implementasikan pipeline produsen-konsumen menggunakan coroutine. Kamu berlatih Lua Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Lua Academy?

Tidak diperlukan pengalaman sebelumnya. Lua Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 4 dari 4.

Berapa lama pelajaran “Pola Produsen-Konsumen” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Lua Academy ini?

Ya. Setiap pelajaran Lua Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Membuat Coroutine
  2. resume dan yield
  3. Status Coroutine
  4. Pola Produsen-Konsumen
← Kembali ke Lua Academy