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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การสร้างโคโรทีน
- resume และ yield
- สถานะโคโรทีน
- รูปแบบผู้ผลิต-ผู้บริโภค