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

การสร้างโคโรทีน

สร้างโคโรทีนด้วย coroutine.create และ coroutine.wrap

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

Coroutine คืออะไร

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

local co = coroutine.create(function()
  print("start")
  coroutine.yield()
  print("resumed")
  coroutine.yield()
  print("done")
end)

print(coroutine.status(co))   -- suspended
coroutine.resume(co)          -- start
print(coroutine.status(co))   -- suspended
coroutine.resume(co)          -- resumed

coroutine.create เทียบกับ coroutine.wrap

coroutine.create(fn) สร้าง coroutine และส่งคืนออบเจ็กต์ coroutine (ชนิด thread) ส่วน coroutine.wrap(fn) สร้าง coroutine และส่งคืนฟังก์ชันที่เมื่อถูกเรียกใช้จะทำงานต่อ ฟังก์ชัน wrap ใช้งานง่ายกว่า แต่จะซ่อนออบเจ็กต์ coroutine

-- create: returns coroutine object
local co = coroutine.create(function(x)
  return x * 2
end)
local ok, val = coroutine.resume(co, 5)
print(ok, val)   -- true  10

-- wrap: returns a resumable function
local gen = coroutine.wrap(function(x)
  return x * 3
end)
print(gen(5))    -- 15

วงจรชีวิตของ Coroutine

coroutine มีสถานะสี่แบบ ได้แก่ suspended (ไม่ได้ทำงาน), running (กำลังทำงาน), dead (ส่งคืนผลลัพธ์หรือเกิดข้อผิดพลาด) และ normal (หยุดชั่วคราวเพราะกลับไปทำงานต่อใน coroutine อื่น) ตรวจสอบสถานะได้ด้วย coroutine.status(co)

local co = coroutine.create(function()
  coroutine.yield()
end)

print(coroutine.status(co))  -- suspended
coroutine.resume(co)          -- runs until yield
print(coroutine.status(co))  -- suspended again
coroutine.resume(co)          -- runs until end
print(coroutine.status(co))  -- dead

การเรียกใช้ Coroutine หลายตัว

สร้าง coroutine หลายตัว แล้วสลับการทำงานระหว่างกันโดยเรียกให้แต่ละตัวทำงานต่อทีละตัว วิธีนี้จำลองการทำงานพร้อมกัน (การทำงานหลายอย่างแบบร่วมมือกัน) coroutine แต่ละตัวจะเก็บสถานะของตัวเองไว้ระหว่างการ yield

local function worker(name, steps)
  for i = 1, steps do
    print(name .. ": step " .. i)
    coroutine.yield()
  end
end

local co1 = coroutine.create(function() worker("A", 3) end)
local co2 = coroutine.create(function() worker("B", 3) end)

for _ = 1, 3 do
  coroutine.resume(co1)
  coroutine.resume(co2)
end
-- A:1, B:1, A:2, B:2, A:3, B:3

การวนซ้ำด้วย coroutine.wrap

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

local function range(n)
  return coroutine.wrap(function()
    for i = 1, n do
      coroutine.yield(i)
    end
  end)
end

for v in range(5) do
  io.write(v .. " ")
end
print()  -- 1 2 3 4 5

ข้อผิดพลาดใน Coroutine

หาก coroutine ทำให้เกิดข้อผิดพลาด coroutine.resume จะส่งคืน false ตามด้วยข้อความแสดงข้อผิดพลาด coroutine จะเปลี่ยนไปเป็นสถานะ dead และไม่สามารถเรียกให้ทำงานต่อได้อีก

local co = coroutine.create(function(x)
  if x < 0 then error("negative input: " .. x) end
  return math.sqrt(x)
end)

local ok, val = coroutine.resume(co, -1)
print(ok, val)    -- false  input:2: negative input: -1
print(coroutine.status(co))  -- dead

-- Can't resume a dead coroutine:
ok, val = coroutine.resume(co)
print(ok, val)    -- false  cannot resume dead coroutine

ข้อมูลประจำตัวของ Coroutine

coroutine.running() ส่งคืน coroutine ที่กำลังทำงานอยู่ในขณะนั้นและค่าบูลีนที่ระบุว่าเป็นเธรดหลักหรือไม่ ใช้คำสั่งนี้ภายใน coroutine เพื่อรับข้อมูลอ้างอิงถึงตัวมันเอง

local co = coroutine.create(function()
  local self, isMain = coroutine.running()
  print("type:", type(self))      -- thread
  print("isMain:", isMain)        -- false
  print("status:", coroutine.status(self)) -- running
end)

coroutine.resume(co)

-- In main thread:
local main, isMain = coroutine.running()
print("main isMain:", isMain)    -- true

ตัวสร้างแบบไม่สิ้นสุด

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

local function naturals(start)
  return coroutine.wrap(function()
    local n = start or 1
    while true do
      coroutine.yield(n)
      n = n + 1
    end
  end)
end

local gen = naturals(1)
for i = 1, 8 do
  io.write(gen() .. " ")
end
print()  -- 1 2 3 4 5 6 7 8

Coroutine ในฐานะงาน

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

local tasks = {}

local function spawn(fn)
  tasks[#tasks+1] = coroutine.create(fn)
end

local function run()
  while #tasks > 0 do
    local alive = {}
    for _, co in ipairs(tasks) do
      coroutine.resume(co)
      if coroutine.status(co) ~= "dead" then
        alive[#alive+1] = co
      end
    end
    tasks = alive
  end
end

spawn(function() for i=1,3 do print("T1:"..i); coroutine.yield() end end)
spawn(function() for i=1,3 do print("T2:"..i); coroutine.yield() end end)
run()

หน่วยความจำของโครูทีน

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

-- Coroutine pool concept
local pool = {}

local function getCoroutine(fn)
  -- Reuse dead coroutine slots
  for i, co in ipairs(pool) do
    if coroutine.status(co) == "dead" then
      pool[i] = coroutine.create(fn)
      return pool[i]
    end
  end
  local co = coroutine.create(fn)
  pool[#pool+1] = co
  return co
end

print("Pool pattern for coroutine reuse")

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

โครูทีนอยู่ในสถานะใดทันทีหลังจาก coroutine.create(fn)?

สรุป: การสร้างโครูทีน

สรุป:

  • coroutine.create(fn) → ออบเจ็กต์โครูทีน; wrap(fn) → ฟังก์ชันที่ดำเนินการต่อได้
  • สถานะ: ถูกพัก → กำลังทำงาน → ถูกพัก/สิ้นสุด
  • coroutine.resume(co, ...) ใช้เริ่มต้นหรือดำเนินการต่อ
  • ข้อผิดพลาดระหว่างการดำเนินการต่อ: false + ข้อความข้อผิดพลาด; โครูทีน → สิ้นสุด
  • ตัวสร้างแบบไม่สิ้นสุดผ่าน while true do yield() end
  • ใช้สำหรับการทำงานหลายงานแบบร่วมมือกันและลำดับแบบประเมินค่าเมื่อจำเป็น

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

บทเรียน “การสร้างโคโรทีน” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “การสร้างโคโรทีน”

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

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

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

บทเรียน “การสร้างโคโรทีน” ใช้เวลานานแค่ไหน

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

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

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

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

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