การส่งต่อการยกเลิกในลำดับชั้น Coroutine
ทำความเข้าใจว่าการยกเลิกไหลผ่านความสัมพันธ์ระหว่าง coroutine แม่และลูกอย่างไร
การส่งต่อการยกเลิกในลำดับชั้น Coroutine เป็นบทเรียน Kotlin Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Kotlin Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
ความสัมพันธ์ระหว่างแม่กับลูก
เมื่อโคโรทีนเปิดใช้งานอีกโคโรทีนหนึ่งด้วย launch โคโรทีนลูกจะเข้าร่วมกับ Job ของแม่ การยกเลิกแม่จะยกเลิกลูกทั้งหมด
import kotlinx.coroutines.*
fun main() = runBlocking {
val parent = launch {
launch { delay(1000); println("child 1") }
launch { delay(1000); println("child 2") }
delay(1000)
println("parent")
}
delay(50)
parent.cancel()
parent.join()
println("All cancelled")
}ความล้มเหลวของลูกทำให้แม่ถูกยกเลิก
หากลูกโยนข้อยกเว้นที่ไม่ใช่การยกเลิก ลูกจะยกเลิกแม่และพี่น้องทั้งหมด นี่คือพฤติกรรมเริ่มต้นของ Job
import kotlinx.coroutines.*
fun main() = runBlocking {
try {
coroutineScope {
launch {
delay(50)
throw RuntimeException("child failed")
}
launch {
delay(1000)
println("sibling — never prints")
}
}
} catch (e: RuntimeException) {
println("Caught: ${e.message}")
}
}การยกเลิกไม่ส่งต่อขึ้นไปยังแม่
การยกเลิกลูกจะไม่ยกเลิกแม่ มีเพียงข้อยกเว้นที่ไม่ได้จัดการเท่านั้นที่ทำเช่นนั้นได้ ส่วนแม่สามารถยกเลิกลูกได้ตามต้องการ
import kotlinx.coroutines.*
fun main() = runBlocking {
val parent = launch {
val child = launch {
delay(1000)
println("child done")
}
delay(50)
child.cancel() // cancels child
child.join()
println("parent still running") // parent is fine
}
parent.join()
}coroutineScope เทียบกับ GlobalScope
coroutineScope จะสร้างขอบเขตลูก ซึ่งการยกเลิกและข้อผิดพลาดจะแพร่ต่อไป ส่วน GlobalScope จะสร้างโคโรทีนไร้เจ้าของที่ไม่มีแม่ ควรหลีกเลี่ยงในการใช้งานจริง
import kotlinx.coroutines.*
fun main() = runBlocking {
try {
coroutineScope {
launch { delay(50); throw RuntimeException("error") }
}
} catch (e: Exception) {
println("coroutineScope propagated: ${e.message}")
}
// GlobalScope.launch { } would NOT propagate to runBlocking
}การยกเลิกส่วนย่อยของลำดับชั้น
launch หรือ async ทุกครั้งจะคืนค่าเป็น Job ให้ยกเลิกงานเพื่อยกเลิกลำดับชั้นย่อยทั้งหมด รวมถึงการเปิดใช้งานที่ซ้อนอยู่
import kotlinx.coroutines.*
fun main() = runBlocking {
val root = launch {
launch {
launch { delay(1000); println("deep") }
delay(1000)
}
}
delay(50)
root.cancel()
root.join()
println("Whole subtree cancelled")
}join() หลังจาก cancel()
ให้เรียก join() หลังจาก cancel() เสมอ เพื่อรอให้โคโรทีนและลูกของมันหยุดทำงานอย่างสมบูรณ์ก่อนดำเนินการต่อ
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
try { delay(1000) }
finally { println("cleanup ran") }
}
delay(50)
job.cancel()
job.join() // waits for finally to complete
println("Proceeded after join")
}cancelAndJoin()
job.cancelAndJoin() เป็นฟังก์ชันอำนวยความสะดวกที่ยกเลิกแล้วจึงเข้าร่วมงาน ซึ่งเทียบเท่ากับ cancel() + join()
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
try { delay(1000) }
finally { println("cleanup") }
}
delay(50)
job.cancelAndJoin() // cancel + join in one call
println("Done")
}การแพร่ผ่าน async
เมื่อใช้ async ข้อยกเว้นจะถูกเก็บไว้ใน Deferred และจะถูกโยนเมื่อเรียก await() ข้อยกเว้นเหล่านั้นยังคงแพร่ไปยังแม่หากไม่ได้จัดการ
import kotlinx.coroutines.*
fun main() = runBlocking {
try {
coroutineScope {
val d = async { throw RuntimeException("async fail") }
d.await() // rethrows here
}
} catch (e: RuntimeException) {
println("Caught from async: ${e.message}")
}
}หลักประกันของการทำงานพร้อมกันแบบมีโครงสร้าง
การทำงานพร้อมกันแบบมีโครงสร้างรับประกันว่าเมื่อขอบเขตเสร็จสิ้น ลูกทั้งหมดจะเสร็จสิ้นแล้ว จะไม่มีโคโรทีนรั่วไหล เพราะโคโรทีนเหล่านั้นจะทำงานจนเสร็จหรือถูกยกเลิก
import kotlinx.coroutines.*
suspend fun doWork() = coroutineScope {
launch { delay(100); println("work 1") }
launch { delay(200); println("work 2") }
// both children complete before doWork returns
}
fun main() = runBlocking {
doWork()
println("All work done")
}แผนภาพการแพร่ของการยกเลิก
ลำดับชั้นมีดังนี้: ยกเลิกแม่ → ลูกทั้งหมดถูกยกเลิก ยกเลิกลูก → ยกเลิกเฉพาะส่วนย่อยนั้น ข้อยกเว้นของลูก → แม่ถูกยกเลิก → พี่น้องถูกยกเลิก
import kotlinx.coroutines.*
fun main() = runBlocking {
// Parent
launch {
val c1 = launch { delay(1000); println("c1") } // child 1
val c2 = launch { delay(1000); println("c2") } // child 2
delay(50)
c1.cancel() // only c1 cancelled
c1.join()
println("c2 still active: ${c2.isActive}")
c2.cancelAndJoin()
}.join()
}วงจรชีวิตของ CoroutineScope ในแอนดรอยด์
ในแอนดรอยด์ viewModelScope จะถูกยกเลิกเมื่อ ViewModel ถูกล้างข้อมูล โคโรทีนทั้งหมดที่เปิดใช้งานจะถูกยกเลิกโดยอัตโนมัติ จึงไม่ต้องล้างข้อมูลด้วยตนเอง
import kotlinx.coroutines.*
// Pseudocode:
// class MyViewModel : ViewModel() {
// fun load() = viewModelScope.launch {
// val data = repo.fetch() // cancelled if VM cleared
// _state.value = data
// }
// }
fun main() = runBlocking { println("viewModelScope cancels on ViewModel.onCleared()") }ตรวจสอบอย่างรวดเร็ว
โคโรทีนพี่น้องจะเป็นอย่างไรเมื่อโคโรทีนลูกโยนข้อยกเว้นที่ไม่ได้จัดการภายใต้ Job ปกติ
ทบทวน
การยกเลิกแม่จะแพร่ต่อไปยังลูกทั้งหมด ความล้มเหลวของลูกจะแพร่ขึ้นไปยังแม่และพี่น้อง (เมื่อใช้ Job ปกติ) ใช้ cancelAndJoin() เพื่อหยุดการทำงานและล้างข้อมูลอย่างเรียบร้อย การทำงานพร้อมกันแบบมีโครงสร้างช่วยให้มั่นใจว่าจะไม่มีโคโรทีนรั่วไหล
เรียนรู้ Kotlin ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 51
- บทเรียน
- 203
คำถามที่พบบ่อย
บทเรียน “การส่งต่อการยกเลิกในลำดับชั้น Coroutine” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การส่งต่อการยกเลิกในลำดับชั้น Coroutine” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Kotlin Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การส่งต่อการยกเลิกในลำดับชั้น Coroutine”
ทำความเข้าใจว่าการยกเลิกไหลผ่านความสัมพันธ์ระหว่าง coroutine แม่และลูกอย่างไร คุณปฏิบัติ Kotlin Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Kotlin Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Kotlin Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การส่งต่อการยกเลิกในลำดับชั้น Coroutine” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Kotlin Academy นี้ได้ไหม
ได้ บทเรียน Kotlin Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การยกเลิกร่วมมือกัน: isActive และ ensureActive
- withTimeout และ withTimeoutOrNull
- การเก็บกวาดด้วย finally และ NonCancellable
- การส่งต่อการยกเลิกในลำดับชั้น Coroutine