Coroutines — แนวคิดหลัก, Job และ Dispatchers ใน Kotlin

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-03-16 เวลาอ่าน: 8 นาที

Coroutines (โครูทีน) คือเธรดน้ำหนักเบาใน Kotlin สำหรับการเขียนโปรแกรมแบบอะซิงโครนัส ซึ่งพร้อมใช้งานผ่านไลบรารี kotlinx.coroutines ตาม JetBrains Kotlin Documentation, 2026, Coroutines ช่วยให้สามารถระงับการทำงานของฟังก์ชันโดยไม่บล็อกเธรด ซึ่งแตกต่างจาก Thread แบบดั้งเดิม โครูทีนทำงานบนพูลเธรดที่จำกัด ทำให้มีน้ำหนักเบากว่าเธรดทั่วไปเป็นพันเท่า Kotlin Coroutines ถูกผสานรวมอย่างสมบูรณ์กับ Android Jetpack, Retrofit, Room และไลบรารียอดนิยมอื่น ๆ ในระบบนิเวศของ Android

ประเด็นสำคัญ

  • Coroutines — เธรด Kotlin น้ำหนักเบาสำหรับโค้ดอะซิงโครนัสที่ไม่มีการบล็อก
  • ฟังก์ชัน suspend — ฟังก์ชันที่สามารถหยุดชั่วคราวและดำเนินต่อได้โดยไม่บล็อกเธรด
  • Dispatcher กำหนดพูลเธรดสำหรับการทำงานของโครูทีน
  • Job — ตัวอธิบายโครูทีนพร้อมการสนับสนุนการยกเลิกและการติดตามสถานะ
  • CoroutineScope จัดการวงจรชีวิตของโครูทีนและการยกเลิกเมื่อเสร็จสิ้น

โครูทีน Kotlin คืออะไร

Coroutines เป็นกลไกการเขียนโปรแกรมแบบอะซิงโครนัสใน Kotlin ที่ทำงานในไลบรารี kotlinx.coroutines ซึ่งแตกต่างจากเธรดของระบบปฏิบัติการ โครูทีนไม่ได้ผูกติดกับเธรดเฉพาะ: สามารถหยุดชั่วคราวบนเธรดหนึ่งและดำเนินต่อบนอีกเธรดหนึ่งได้ เธรดเดียวสามารถทำงานโครูทีนได้หลายพันตัว โดยสลับระหว่างกันด้วยค่าใช้จ่ายเพียงเล็กน้อย

โครูทีนปรากฏใน Kotlin 1.3 (2018) เป็นฟีเจอร์ทดลองและกลายเป็นเสถียรใน Kotlin 1.5 (2021) Coroutines แก้ปัญหา callback hell ในลักษณะเดียวกับ async/await แต่ให้ API ที่สมบูรณ์กว่า: ช่องสัญญาณ (Channel), Flow, การจัดการข้อยกเว้นในลำดับชั้น Job และการผสานรวมโดยตรงกับ Android Lifecycle

ตามข้อมูลของ JetBrains (2025) โครูทีนแต่ละตัวใช้หน่วยความจำประมาณ 100 ไบต์ ในขณะที่เธรดทั่วไปใช้ 1+ MB ซึ่งทำให้สามารถเรียกใช้โครูทีนหลายล้านตัวในแอปพลิเคชันเดียวโดยไม่มีความเสี่ยง OutOfMemoryError ความเบาของโครูทีนนี่เองที่ทำให้เป็นเครื่องมือที่ต้องการสำหรับการทำงานแบบอะซิงโครนัสใน Android

โครูทีนทำงานภายในอย่างไร

โครูทีน Kotlin แต่ละตัวถูกคอมไพล์เป็นเครื่องสถานะผ่าน Continuation Passing Style (CPS) คอมไพเลอร์เพิ่มพารามิเตอร์ Continuation ที่ซ่อนอยู่ให้กับทุกฟังก์ชัน suspend Continuation ประกอบด้วยจุดดำเนินต่อและตัวแปรท้องถิ่นทั้งหมด เมื่อโครูทีนหยุดชั่วคราว runtime จะบันทึก Continuation และเมื่อดำเนินต่อ จะกู้คืนบนเธรดใด ๆ ที่มีอยู่ในพูล Dispatcher

ฟังก์ชัน suspend: การหยุดชั่วคราวและการดำเนินต่อ

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

กลไกง่าย ๆ: เมื่อฟังก์ชัน suspend เรียกฟังก์ชัน suspend อื่น มันจะหยุดชั่วคราวที่จุดนั้น ปล่อยเธรด หลังจากฟังก์ชันที่ถูกเรียกเสร็จสิ้น runtime จะดำเนินการต่อจากตำแหน่งที่บันทึกไว้ สิ่งนี้เรียกว่าการยกเลิกแบบร่วมมือ (cooperative cancellation) — ไม่มีเธรดใดถูกบล็อก

  • การหยุดชั่วคราว — โครูทีนปล่อยเธรดโดยไม่บล็อก
  • การดำเนินต่อ — โครูทีนดำเนินต่อจากจุดที่หยุดชั่วคราว
  • เธรด — โครูทีนสามารถหยุดชั่วคราวบนเธรด A และดำเนินต่อบนเธรด B
  • ข้อยกเว้น — จัดการผ่าน try/catch เช่นเดียวกับโค้ดซิงโครนัส

สำคัญ: ฟังก์ชัน suspend ไม่ได้เป็นอะซิงโครนัสโดยค่าเริ่มต้น ลำดับการทำงานยังคงเป็นลำดับหากไม่ได้ใช้ launch หรือ async suspend เพียงอนุญาตให้ฟังก์ชันหยุดชั่วคราวโดยไม่บล็อกเธรดและเป็นส่วนหนึ่งของบริบทโครูทีน Continuation Passing Style เป็นโมเดลการคอมไพล์ที่ฟังก์ชัน suspend แต่ละตัวรับ callback Continuation ที่ซ่อนอยู่ และคอมไพเลอร์สร้างเครื่องสถานะเพื่อจัดการการหยุดชั่วคราวและการดำเนินต่อ

CoroutineScope และการทำงานพร้อมกันแบบมีโครงสร้าง

CoroutineScope คือบริบทที่กำหนดวงจรชีวิตของโครูทีน โครูทีนทั้งหมดต้องถูกเริ่มภายในขอบเขต เมื่อขอบเขตถูกยกเลิก (เช่น เมื่อ Activity สิ้นสุด) โครูทีนลูกทั้งหมดจะถูกยกเลิกโดยอัตโนมัติ ซึ่งป้องกันการรั่วไหลของงานเบื้องหลัง Android Jetpack มีขอบเขตพร้อมใช้สำหรับแต่ละคอมโพเนนต์: viewModelScope สำหรับ ViewModel และ lifecycleScope สำหรับ Activity และ Fragment ซึ่งจะถูกยกเลิกโดยอัตโนมัติเมื่อคอมโพเนนต์ที่เกี่ยวข้องถูกทำลาย

การทำงานพร้อมกันแบบมีโครงสร้าง (Structured Concurrency) เป็นหลักการที่รับประกันว่าโครูทีนจะไม่เสร็จสมบูรณ์จนกว่าโครูทีนลูกทั้งหมดจะเสร็จสมบูรณ์ ลำดับชั้น Job ก่อตัวเป็นต้นไม้: โครูทีนรากสร้าง parent job ลูกสร้าง child jobs การยกเลิก parent job แพร่กระจายไปยังลูกทั้งหมด Structured Concurrency คือความแตกต่างพื้นฐานระหว่างโครูทีนและเธรด

Scopeใช้ที่ไหนการยกเลิก
GlobalScopeเฉพาะงานเดมอนไม่ถูกยกเลิกอัตโนมัติ
viewModelScopeAndroid ViewModelเมื่อล้าง ViewModel
lifecycleScopeAndroid Activity/Fragmentเมื่อ lifecycle ถูกทำลาย
coroutineScopeภายในฟังก์ชัน suspendเมื่อ parent job ถูกยกเลิก

SupervisorJob สำหรับการจัดการข้อผิดพลาด

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

Dispatchers และตัวสร้างโครูทีน

Dispatchers กำหนดว่าโครูทีนจะทำงานบนเธรดใด Dispatchers.Main — เธรด UI หลักของ Android Dispatchers.IO — พูลสำหรับการดำเนินการที่บล็อก (เครือข่าย, ดิสก์) Dispatchers.Default — สำหรับงานที่ใช้ CPU มาก Dispatchers.Unconfined — เริ่มต้นในเธรดปัจจุบันแต่ไม่รับประกันว่าจะอยู่บนเธรดนั้น การเลือก Dispatcher ที่ถูกต้องสำคัญต่อประสิทธิภาพ: งาน IO บน Default จะบล็อกพูลคำนวณ ในขณะที่งาน CPU บน IO จะสร้างเธรดที่ไม่จำเป็น

withContext — ฟังก์ชันสำหรับเปลี่ยน Dispatcher ภายในโครูทีน ตัวอย่างเช่น ฟังก์ชัน suspend ที่แยกวิเคราะห์ JSON สามารถสลับไปที่ Dispatchers.Default สำหรับการคำนวณและกลับไปที่ Dispatchers.Main สำหรับการอัปเดต UI withContext เป็นตัวสร้างที่ใช้บ่อยที่สุดในการพัฒนา Android

ตัวสร้างโครูทีนหลักสามตัว

launch — เริ่มโครูทีน คืนค่า Job ไม่คืนผลลัพธ์ (fire-and-forget) async — เริ่มโครูทีน คืนค่า Deferred ซึ่งสามารถรับผลลัพธ์ได้ผ่าน await runBlocking — บล็อกเธรดปัจจุบันเพื่อทำงานโครูทีน (เฉพาะสำหรับการทดสอบและฟังก์ชัน main) การเลือกตัวสร้าง ขึ้นอยู่กับสถานการณ์: launch เหมาะสำหรับเหตุการณ์และการอัปเดต async สำหรับงานที่มีผลลัพธ์ runBlocking เฉพาะสำหรับการทดสอบหรือจุดเริ่มต้น

ตัวอย่างโค้ดกับโครูทีนใน Kotlin

ลองพิจารณาสามสถานการณ์เชิงปฏิบัติ: โครูทีนพื้นฐานกับ launch, การเรียกแบบขนานกับ async และการจัดการข้อผิดพลาดกับ SupervisorJob

การเริ่มโครูทีนด้วย launch

viewModelScope.launch เริ่มโครูทีนในบริบท ViewModel เมื่อ ViewModel ถูกล้าง โครูทีนจะถูกยกเลิกโดยอัตโนมัติ

kotlin
class ProfileViewModel : ViewModel() {
    fun loadUser() {
        viewModelScope.launch(Dispatchers.IO) {
            val user = api.fetchUser()
            withContext(Dispatchers.Main) {
                showUser(user)
            }
        }
    }
}

คำขอแบบขนานด้วย async

coroutineScope กับ async เริ่มสามคำขอแบบขนาน ผลลัพธ์จะถูกรวบรวมผ่าน .await() หากคำขอใดล้มเหลว คำขอทั้งหมดจะถูกยกเลิก

kotlin
suspend fun loadDashboard(): Dashboard = coroutineScope {
    val user = async { api.fetchUser() }
    val posts = async { api.fetchPosts() }
    val stats = async { api.fetchStats() }
    Dashboard(user.await(), posts.await(), stats.await())
}

การจัดการข้อผิดพลาดด้วย SupervisorJob

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

kotlin
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
    try { api.fetchUsers() } catch (e: Exception) { log(e) }
}
scope.launch {
    try { api.fetchPosts() } catch (e: Exception) { log(e) }
}

โครูทีน vs เธรด: การเปรียบเทียบและสถานการณ์

เธรด (Thread) เป็นพื้นฐานของระบบปฏิบัติการ แต่ละเธรดมีสแต็กของตัวเอง (~1 MB) และต้องใช้การเรียกของระบบเพื่อสร้างและสลับ โครูทีน เป็นพื้นฐานของภาษา ไม่ผูกติดกับระบบปฏิบัติการ ใช้ Continuation เพื่อบันทึกสถานะและสลับที่ระดับ runtime โดยไม่ต้องเรียกของระบบ

  • หน่วยความจำ — เธรด ~1 MB, โครูทีน ~100 ไบต์ ต่างกัน 10,000 เท่า
  • การสร้าง — เธรด ~1 µs syscall, โครูทีน ~0.01 µs ที่ระดับ JVM
  • การสลับ — เธรด ~0.1 µs (syscall), โครูทีน ~0.001 µs (continuation)
  • สูงสุด — เธรดหลายพันตัว vs โครูทีนหลายล้านตัวต่ออุปกรณ์
  • การยกเลิก — เธรดไม่สามารถยกเลิกจากภายนอกได้ (เลิกใช้ Thread.stop), โครูทีนสามารถยกเลิกผ่าน Job.cancel()

ตามข้อมูลของ Google (2025) การใช้โครูทีนแทนเธรดช่วยลดการใช้หน่วยความจำสำหรับงานเบื้องหลังในแอปพลิเคชัน Android ลง 90–95% ไลบรารี Android สมัยใหม่ทั้งหมด (Retrofit, Room, WorkManager) มีการสนับสนุนโครูทีนในตัวผ่านฟังก์ชัน suspend Ktor (เฟรมเวิร์กไคลเอนต์ HTTP ของ JetBrains) ก็สร้างบนโครูทีนทั้งหมด โดยให้ฟังก์ชัน suspend สำหรับทุกคำขอโดยไม่มี API แบบ callback Room รองรับโครูทีนผ่านฟังก์ชัน suspend ใน DAO ซึ่งช่วยให้ดำเนินการค้นหาฐานข้อมูลโดยไม่บล็อกเธรดหลัก

เมื่อใดควรใช้เธรดแทนโครูทีน

เธรดยังคงจำเป็นสำหรับ โค้ดเนทีฟ ผ่าน JNI, การเรียกที่บล็อกซึ่งใช้ CPU มากโดยไม่จำกัดเวลา (การเรนเดอร์วิดีโอ, การจำลอง) และเมื่อรวมกับไลบรารี C สำหรับสิ่งอื่นทั้งหมด — โครูทีน

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

โครูทีนแตกต่างจากเธรดอย่างไร?

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

Dispatchers.IO คืออะไรและแตกต่างจาก Default อย่างไร?

Dispatchers.IO ออกแบบมาสำหรับการดำเนินการ I/O ที่บล็อก (เครือข่าย, ไฟล์) และสามารถสร้างเธรดใหม่เมื่อจำเป็น Dispatchers.Default มีพูลขนาดคงที่ (จำนวนคอร์ CPU) สำหรับการคำนวณที่ใช้ CPU มาก

จะยกเลิกโครูทีนที่กำลังทำงานได้อย่างไร?

Job.cancel() ยกเลิกโครูทีนและลูกทั้งหมด หากต้องการตรวจสอบการยกเลิกภายในโครูทีน ให้ใช้ ensureActive() — มันจะโยน CancellationException ถ้าโครูทีนถูกยกเลิก

สามารถใช้โครูทีนกับ RxJava ได้หรือไม่?

ได้ — ผ่านไลบรารี kotlinx-coroutines-rx3 ซึ่งมีฟังก์ชัน awaitSingle, awaitFirst และอื่น ๆ สำหรับแปลง Observable/Single เป็นฟังก์ชัน suspend และกลับผ่าน flowable

Flow ในโครูทีนคืออะไร?

Flow คือสตรีมข้อมูลอะซิงโครนัสแบบเย็น ซึ่งเทียบเท่ากับ RxJava Observable ในโครูทีน Flow ปล่อยค่าตามลำดับและเสร็จสมบูรณ์ด้วยข้อยกเว้นหรือความสำเร็จ รองรับ map, filter, catch และตัวดำเนินการอื่น ๆ

สรุป

  • Coroutines — เธรด Kotlin น้ำหนักเบาพร้อมการระงับที่ไม่บล็อกผ่าน Continuation Passing Style
  • suspend — คำสำคัญสำหรับทำเครื่องหมายฟังก์ชันที่สามารถระงับได้
  • Dispatchers จัดการพูลเธรด: Main, IO, Default ตามลำดับ
  • CoroutineScope ผูกวงจรชีวิตโครูทีนกับคอมโพเนนต์ (Activity, ViewModel)
  • launch เริ่มโครูทีนโดยไม่มีผลลัพธ์, async/await — มีผลลัพธ์
  • Structured Concurrency รับประกันการยกเลิกตามลำดับชั้นของโครูทีนลูก
  • โครูทีน vs เธรด — โครูทีนเบากว่า 10,000 เท่าและเป็นมาตรฐานสำหรับ Android

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม