0Pricing
Lua Academy · บทเรียน

รูปแบบผู้ผลิต-ผู้บริโภค

สร้าง pipeline ผู้ผลิต-ผู้บริโภคด้วยโคโรทีน

รูปแบบผู้ผลิต-ผู้บริโภค เป็นบทเรียน Lua Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Lua Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน

อธิบายรูปแบบ

รูปแบบผู้ผลิตและผู้บริโภคด้วยโครูทีนคือ ผู้ผลิตสร้างข้อมูลและ yield แต่ละรายการ ส่วน ผู้บริโภครับรายการทีละรายการ ทั้งสองฝ่ายไม่จำเป็นต้องรู้รายละเอียดการทำงานของอีกฝ่าย เพราะสื่อสารกันผ่าน yield/resume วิธีนี้แยกการสร้างข้อมูลออกจากการประมวลผลข้อมูล

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

ผู้ผลิตแบบไม่สิ้นสุด

โครูทีนของผู้ผลิตสามารถ yield ลำดับข้อมูลที่ไม่สิ้นสุดได้ ผู้บริโภคเป็นผู้ควบคุมว่าจะหยุดเมื่อใด เหมาะอย่างยิ่งสำหรับแหล่งข้อมูลแบบสตรีม เช่น ค่าที่อ่านจากเซนเซอร์ เหตุการณ์จากการบันทึกข้อมูล และลำดับข้อมูลที่สร้างขึ้น

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

ผู้บริโภคในรูปโครูทีน

ผู้บริโภคก็สามารถเป็นโครูทีนได้เช่นกัน ทำให้เกิดคู่ผู้ผลิตและผู้บริโภคที่มีโครงสร้างสมมาตรอย่างสมบูรณ์ ฟังก์ชัน “ตัวขับเคลื่อน” ตัวที่สามจะประสานงานทั้งสองฝ่าย วิธีนี้มีประโยชน์สำหรับสายงานประมวลผลแบบมีบัฟเฟอร์ ซึ่งผู้ผลิตและผู้บริโภคทำงานด้วยอัตราที่ต่างกัน

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

แรงดันย้อนกลับ

แรงดันย้อนกลับคือกรณีที่ผู้บริโภคส่งสัญญาณให้ผู้ผลิตทำงานช้าลง สำหรับโครูทีน เรื่องนี้เกิดขึ้นโดยธรรมชาติ ผู้ผลิตจะ yield หลังแต่ละรายการและรอให้ผู้บริโภคร้องขอรายการถัดไป หากผู้บริโภคทำงานช้า ผู้ผลิตก็เพียงรอ

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

การประมวลผลเป็นชุด

ผู้ผลิตแบบรวมชุดจะรวบรวมรายการจำนวน N รายการก่อน yield เป็นหนึ่งชุด ผู้บริโภคจะรับและประมวลผลชุดข้อมูลที่สมบูรณ์ วิธีนี้ลดค่าใช้จ่ายในการประสานงานสำหรับผู้ผลิตที่ทำงานด้วยความถี่สูง

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

ผู้ผลิตบรรทัดจากไฟล์

อ่านไฟล์แบบประเมินค่าเมื่อจำเป็น: โครูทีนของผู้ผลิตจะอ่านทีละบรรทัดและ yield แต่ละบรรทัด ผู้บริโภคจึงประมวลผลบรรทัดต่าง ๆ ได้โดยไม่ต้องโหลดไฟล์ทั้งหมดเข้าสู่หน่วยความจำ

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)

ขั้นแปลงข้อมูล

แทรกขั้นแปลงข้อมูลระหว่างผู้ผลิตกับผู้บริโภค ขั้นแปลงข้อมูลจะอ่านจากโครูทีนหนึ่งและ yield ค่าที่ประมวลผลแล้วไปยังอีกโครูทีนหนึ่ง สร้างสายงานข้อมูลโดยเชื่อมขั้นเหล่านี้เข้าด้วยกัน

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

การส่งต่อข้อผิดพลาดในสายงานประมวลผล

ข้อผิดพลาดในสายงานประมวลผลของโครูทีนจะถูกส่งต่อผ่านสถานะสิ้นสุดหรือผ่าน pcall ให้ห่อหุ้มแต่ละขั้นของสายงานประมวลผลด้วย pcall เพื่อดักจับและจัดการข้อผิดพลาดอย่างเหมาะสม โดยไม่ทำให้สายงานทั้งหมดหยุดทำงาน

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

รวมผู้ผลิต

รวมผู้ผลิตหลายตัวให้เป็นผู้ผลิตตัวเดียว โดยวนสลับระหว่างผู้ผลิตที่ยังทำงานอยู่ทั้งหมดและ yield รายการของแต่ละตัวตามลำดับ หยุดเมื่อผู้ผลิตทั้งหมดส่งข้อมูลครบแล้ว

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

กรณีใช้งานจริง

สายงานประมวลผลบันทึกข้อมูล: ผู้ผลิตอ่านบรรทัดบันทึกข้อมูล ขั้นกรองเก็บเฉพาะบรรทัดข้อผิดพลาด ขั้นแปลงข้อมูลดึงข้อมูลสำคัญ และผู้บริโภครวมข้อมูลตามประเภทข้อผิดพลาด แต่ละขั้นเป็นโครูทีนอิสระที่ทดสอบได้

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

ตรวจสอบความเข้าใจอย่างรวดเร็ว

รูปแบบโครูทีนผู้ผลิตและผู้บริโภคจัดการแรงดันย้อนกลับอย่างไร?

สรุป: ผู้ผลิตและผู้บริโภค

สรุป:

  • ผู้ผลิต yield รายการ ส่วนผู้บริโภคขับเคลื่อนด้วยการเรียก resume
  • ผู้ผลิตแบบไม่สิ้นสุด: while true do yield() end
  • สายงานประมวลผล: เชื่อมโครูทีนแปลงข้อมูลระหว่างผู้ผลิตกับผู้บริโภค
  • แรงดันย้อนกลับเกิดขึ้นโดยอัตโนมัติ ผู้ผลิตจะรอผู้บริโภค
  • ใช้ขั้นรวมชุด กรอง และรวมข้อมูลเป็นตัวห่อหุ้มโครูทีน
  • ใช้ pcall ในขั้นของสายงานประมวลผลเพื่อแยกข้อผิดพลาด

คำถามที่พบบ่อย

บทเรียน “รูปแบบผู้ผลิต-ผู้บริโภค” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “รูปแบบผู้ผลิต-ผู้บริโภค” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Lua Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “รูปแบบผู้ผลิต-ผู้บริโภค”

สร้าง pipeline ผู้ผลิต-ผู้บริโภคด้วยโคโรทีน คุณปฏิบัติ Lua Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Lua Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Lua Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “รูปแบบผู้ผลิต-ผู้บริโภค” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Lua Academy นี้ได้ไหม

ได้ บทเรียน Lua Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การสร้างโคโรทีน
  2. resume และ yield
  3. สถานะโคโรทีน
  4. รูปแบบผู้ผลิต-ผู้บริโภค
← กลับไปที่ Lua Academy