Coroutine vs Thread: สั่งพนักงานยืนรอ หรือจ้างนินจาสลับโต๊ะ?
⏱️ ใช้เวลาอ่านประมาณ: 4 นาที 15 วินาที
ถ้าคุณเขียนโค้ดแล้วสั่ง Thread.sleep(2000) หรือยิง
Request ข้าม Network แล้วต้องรอคำตอบ... คุณรู้ไหมว่าเบื้องหลัง CPU
กำลังทำอะไรอยู่?
คำตอบสั้นๆ: มันไม่ได้ทำห่าอะไรเลย ยืนเฉยๆ เสียค่าแรงฟรี
และนี่คือสาเหตุที่ทำไมระบบสมัยก่อนที่รันด้วย Traditional Thread พอลูกค้าแห่กันเข้ามาระดับหมื่นคนพร้อมกัน Server ถึงคอพับคออ่อน ทั้งที่ CPU โหลดแค่ 15%!
🍽️ อุปมาภัตตาคาร: ปัญหาของ Traditional OS Thread
ลองจินตนาการถึง ร้านอาหารแบบ Traditional Thread:
- บริกร 1 คน (Thread) รับออเดอร์โต๊ะที่ 1 เสร็จแล้วเดินเอาใบออเดอร์ไปส่งในครัว (Database / API ภายนอก)
- ระหว่างที่พ่อครัวกำลังทอดสเต๊ก 3 นาที บริกรคนนี้จะ ยืนกอดอกนิ่งๆ จ้องกระทะ ไม่ขยับไปไหนเลย (Blocking)
- ถ้ามีลูกค้าใหม่เดินเข้ามา 100 โต๊ะ? ผู้จัดการร้าน (OS) ต้องจ้างบริกรเพิ่ม 100 คนทันที!
ปัญหาคือบริกร 1 คน (1 Thread ใน OS) มีค่าตัวแพงมาก:
- กินพื้นที่กระเป๋าเสื้อ (Stack Memory) ราวๆ 1 MB ต่อคน
- ถ้าจ้าง 2,000 คน แค่ยืนเฉยๆ ก็กินแรมไปแล้ว 2 GB
- เวลาสลับให้คนนู้นคุย คนนี้หยุด (Context Switch) ผู้จัดการร้านต้องเหนื่อยจดโน้ตจนสมองล้าไปหมด
⚡ ยินดีต้อนรับสู่โลก Coroutine: ไม่ยืนรอ แต่สลับโต๊ะ!
แนวคิดของ Coroutine (หรือ Virtual Thread ในฝั่ง Java ยุคใหม่) เปลี่ยนวิธีคิดใหม่หมดจด:
เราใช้บริกรตัวจริง (OS Thread) แค่ไม่กี่คนพอ (เช่น เท่ากับจำนวนคอร์ของ CPU 4-8 คน) แต่สอนวิชานินจาที่เรียกว่า Suspend & Resume ให้พวกเขา:
"เมื่อไหร่ก็ตามที่ต้องรอ (I/O, Network, DB) ให้วางบุ๊กมาร์กไว้ แล้วสลับตัวไปดูแลโต๊ะอื่นทันที พอของในครัวเสร็จ ค่อยกลับมาเก็บงานต่อ!"
ใน Kotlin เราแค่เติมคำว่า suspend หน้าฟังก์ชัน:
// ไม่ Block Thread! แค่ปล่อยมือให้คนอื่นทำงานต่อ
return api.getOrder(id)
}
และที่สำคัญคือ Coroutine ไม่ใช่ OS Thread แต่เป็นแค่ Object ตัวเล็กๆ ในหน่วยความจำ ที่กินพื้นที่เพียงไม่กี่ร้อย Bytes... คุณสามารถรัน Coroutines พร้อมกัน 100,000 ตัว ได้บนแล็ปท็อปธรรมดาๆ โดยที่พัดลมเครื่องไม่แม้แต่จะกระดิก!
💡 5-Min Takeaway
งาน Backend ยุคนี้ส่วนใหญ่เสียเวลาไปกับการ "รอ" (รอ Database คืนค่า, รอ Third-party API ตอบกลับ) การใช้ Traditional Thread ไปยืนขวางรอคือการผลาญทรัพยากรโดยเปล่าประโยชน์ การเปลี่ยนมาใช้ Non-blocking / Coroutine คือการรีดศักยภาพของฮาร์ดแวร์เดิมให้รองรับ Concurrent User ได้มากกว่าเดิมเป็นสิบเท่า โดยไม่ต้องจ่ายค่าเซิร์ฟเวอร์เพิ่มสักบาท