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

resume และ yield

แลกเปลี่ยนข้อมูลระหว่างผู้เรียกกับโคโรทีนด้วย resume/yield

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

การส่งค่าไปยังโครูทีน

อาร์กิวเมนต์ที่ส่งให้กับ coroutine.resume ครั้งแรกจะกลายเป็นพารามิเตอร์ของฟังก์ชันในตัวโครูทีน อาร์กิวเมนต์ที่ส่งให้กับการดำเนินการต่อครั้งถัดไปจะถูกส่งคืนโดยการเรียก coroutine.yield() ที่ทำให้โครูทีนหยุดชั่วคราว

local co = coroutine.create(function(a, b)
  print("received:", a, b)        -- 10  20
  local c = coroutine.yield()     -- pauses
  print("after yield:", c)        -- 30
end)

coroutine.resume(co, 10, 20)  -- first call: passes a,b
coroutine.resume(co, 30)      -- subsequent: passed to yield

ค่าจาก yield

ค่าที่ส่งให้กับ coroutine.yield(val1, val2) จะกลายเป็นค่าที่ส่งคืนจากการเรียก coroutine.resume() ซึ่งหยุดชั่วคราวที่ yield ดังนั้น yield จึง “ส่งคืน” ค่าไปยังผู้เรียก

local co = coroutine.create(function()
  coroutine.yield(1, "hello")
  coroutine.yield(2, "world")
  return 3, "done"
end)

local ok, a, b = coroutine.resume(co)
print(ok, a, b)   -- true  1  hello

ok, a, b = coroutine.resume(co)
print(ok, a, b)   -- true  2  world

ok, a, b = coroutine.resume(co)
print(ok, a, b)   -- true  3  done

การสื่อสารสองทิศทาง

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

local co = coroutine.create(function(x)
  while true do
    x = coroutine.yield(x * x)  -- yield x^2, get next x
  end
end)

coroutine.resume(co)  -- start (x=nil initially)
local ok, sq
ok, sq = coroutine.resume(co, 3); print(sq)  -- 9
ok, sq = coroutine.resume(co, 5); print(sq)  -- 25
ok, sq = coroutine.resume(co, 7); print(sq)  -- 49

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

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

local function producer(items)
  return coroutine.create(function()
    for _, item in ipairs(items) do
      coroutine.yield(item)
    end
  end)
end

local pro = producer({"apple","banana","cherry"})

-- Consumer drives the loop
while true do
  local ok, item = coroutine.resume(pro)
  if not ok or item == nil then break end
  print("consumed:", item)
end

สายงานประมวลผลด้วยโครูทีน

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

local function source(items)
  return coroutine.wrap(function()
    for _, v in ipairs(items) do coroutine.yield(v) end
  end)
end

local function filter(iter, pred)
  return coroutine.wrap(function()
    for v in iter do
      if pred(v) then coroutine.yield(v) end
    end
  end)
end

local function map(iter, fn)
  return coroutine.wrap(function()
    for v in iter do coroutine.yield(fn(v)) end
  end)
end

local pipeline = map(filter(source({1,2,3,4,5,6}),
  function(n) return n%2==0 end),
  function(n) return n*n end)

for v in pipeline do io.write(v.." ") end
print()  -- 4 16 36

โครูทีนสำหรับจำลองการทำงานแบบอะซิงโครนัส

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

local scheduler = {}
local current = nil

local function await(key)
  coroutine.yield(key)  -- tell scheduler what we need
  return coroutine.yield()  -- wait for result
end

local co = coroutine.create(function()
  local data = await("fetch:users")
  print("Got users:", data)
end)

-- Start coroutine
local ok, want = coroutine.resume(co)
print("Coroutine wants:", want)  -- fetch:users
-- Simulate delivering the result:
coroutine.resume(co, {{name="Alice"},{name="Bob"}})

yield ภายในฟังก์ชัน

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

local function yieldTwice(label)
  coroutine.yield(label .. ":1")
  coroutine.yield(label .. ":2")
end

local co = coroutine.create(function()
  yieldTwice("A")
  yieldTwice("B")
end)

for i = 1, 4 do
  local ok, v = coroutine.resume(co)
  print(v)
end
-- A:1, A:2, B:1, B:2

โครูทีนไม่ใช่เธรด

โครูทีนของ Lua ไม่ใช่เธรดของ OS จะมีโครูทีนทำงานได้ครั้งละเพียงหนึ่งตัวเท่านั้น โดยไม่มีการแย่งเวลาทำงานล่วงหน้าและไม่มีการทำงานแบบขนาน โครูทีนทั้งหมดใช้เธรดของ OS เดียวกัน หากต้องการทำงานแบบขนานอย่างแท้จริง คุณต้องใช้สถานะ Lua หลายชุดในเธรดของ OS แยกกัน

-- This is NOT parallel - interleaved execution
local function task(name, n)
  for i = 1, n do
    print(name, i)
    coroutine.yield()
  end
end

local t1 = coroutine.create(function() task("A", 3) end)
local t2 = coroutine.create(function() task("B", 3) end)

-- Must explicitly schedule:
for _ = 1, 3 do
  coroutine.resume(t1)
  coroutine.resume(t2)
end
-- A1, B1, A2, B2, A3, B3 (interleaved, NOT parallel)

สถานะหลังการดำเนินการต่อ

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

local co = coroutine.create(function()
  for i = 1, 3 do coroutine.yield(i) end
end)

while coroutine.status(co) ~= "dead" do
  local ok, val = coroutine.resume(co)
  if ok and val ~= nil then
    print("val:", val)
  end
end
-- val: 1, val: 2, val: 3

การ yield หลายครั้งในการดำเนินการต่อครั้งเดียว

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

local co = coroutine.create(function()
  local x = coroutine.yield("first")
  print("got:", x)
  local y = coroutine.yield("second")
  print("got:", y)
end)

local _, v1 = coroutine.resume(co)         -- starts, yields "first"
print("yielded:", v1)                       -- first
local _, v2 = coroutine.resume(co, "a")   -- passes "a", yields "second"
print("yielded:", v2)                       -- second
coroutine.resume(co, "b")                   -- passes "b", coroutine ends

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

ค่าที่ส่งให้กับ coroutine.yield(v1, v2) จะกลายเป็นอะไร?

สรุป: resume และ yield

สรุป:

  • อาร์กิวเมนต์ของ resume ครั้งแรก → พารามิเตอร์ของตัวโครูทีน
  • อาร์กิวเมนต์ของ resume ครั้งถัดไป → ค่าที่ yield ก่อนหน้าส่งคืน
  • อาร์กิวเมนต์ของ yield → ค่าที่ resume ซึ่งทำให้เกิด yield ส่งคืน
  • สองทิศทาง: resume/yield แต่ละครั้งเป็นการแลกเปลี่ยน
  • สามารถใช้ yield จากฟังก์ชันที่เรียกซ้อนกันระดับใดก็ได้
  • โครูทีนทำงานแบบร่วมมือกัน ไม่ใช่แบบขนาน

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

บทเรียน “resume และ yield” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “resume และ yield”

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

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

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

บทเรียน “resume และ yield” ใช้เวลานานแค่ไหน

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

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

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

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

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