Coroutine 有三大要素:CoroutineScope、suspend 函式、Dispatcher。其中 suspend 函式負責處理非同步任務,當 Coroutine 執行到 suspend 函式時,這個 Coroutine 會被掛起(suspend),等任務完成之後再恢復執行。
Kotlin Coroutine 提供了一些內建的 suspend 函式,本章先看最常見的一個:delay。
為什麼不用 Thread.sleep#
過去在執行緒(Thread)上想暫停一下,會使用 Thread.sleep()。問題是 sleep 會阻塞整個執行緒,這段期間執行緒什麼事都做不了。
對應到 Coroutine 的情境,如果在 Coroutine 內呼叫 Thread.sleep(),就會把底層執行緒卡住,連同其他要在這個 Dispatcher 上跑的 Coroutine 都會被一起拖住。
fun main() = runBlocking {
launch {
Thread.sleep(100L)
println("Coroutine 1 ${Thread.currentThread().name}")
}
launch {
println("Coroutine 2 ${Thread.currentThread().name}")
}
}第一個 launch 在 Thread.sleep(100L) 期間把執行緒占住,所以第二個 launch 沒辦法接手;輸出順序會是 Coroutine 1 先、Coroutine 2 後。
IDE 會在 Coroutine 中使用
Thread.sleep()的位置顯示 Inappropriate blocking method call 警告,提醒你不要在 Coroutine 裡呼叫會阻塞執行緒的方法。
改用 delay#
delay() 不會阻塞執行緒,它只是把目前這個 Coroutine 切到等待狀態。執行緒在等待期間可以去執行同一個 Dispatcher 上的其他 Coroutine。
fun main() = runBlocking {
launch {
delay(100L)
println("Coroutine 1 ${Thread.currentThread().name}")
}
launch {
println("Coroutine 2 ${Thread.currentThread().name}")
}
}第一個 launch 呼叫 delay() 後,這個 Coroutine 進入等待,執行緒被釋放出來給第二個 launch;等到 100 毫秒結束,第一個 Coroutine 才從暫停的位置繼續往下執行。最後印出的順序會是 Coroutine 2 先、Coroutine 1 後。
小結#
Thread.sleep()會阻塞執行緒;delay()只暫停目前的 Coroutine,執行緒仍可以服務其他 Coroutine。- 在 Coroutine 內想做「等一下」這件事,請用
delay(),不要用Thread.sleep()。
原文出處#
- 原書/iThome:https://ithelp.ithome.com.tw/articles/10266141