Coroutine 跟 thread 的關係
Coroutine 通常可以理解成輕量化的 thread,但實際運作還是需要被排程到作業系統層級的 thread,然後再被排程到某個 CPU來執行:
相對於 thread,使用 coroutine 的好處是, coroutine 之間的切換快速,需要耗用的系統資源也比較小。
Coroutine 如何排程?
Kotlin 的 coroutine 會被分派到那個 thread 是由呼叫 coroutine builder 時提供的 CoroutineContext
參數來決定。
透過觀察這個範例的輸出,我們可以了解不同 CoroutineContext
的行為:
class CoroutineContextActivity : ConsoleActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
logThread("Begin onCreate")
launch(UI) {
logThread("Begin launch(UI)")
delay(10_000)
logThread("End launch(UI)")
}
launch(CommonPool) {
logThread("Begin launch(CommonPool)")
delay(10_000)
logThread("End launch(CommonPool)")
}
launch(Unconfined) {
logThread("Begin launch(Unconfined)")
delay(10_000)
logThread("End launch(Unconfined)")
}
launch(newSingleThreadContext("MyOwnThread")) {
logThread("Begin launch(newSingleThreadContext)")
delay(10_000)
logThread("End launch(newSingleThreadContext)")
}
logThread("End onCreate")
}
fun logThread(msg: String) {
println("$msg: ${Thread.currentThread().name}")
}
}
結果:
1:48:50:866 ( 1) Begin onCreate: main
1:48:50:937 ( 1) Begin launch(Unconfined): main
1:48:50:938 (1719) Begin launch(CommonPool): ForkJoinPool.commonPool-worker-2
1:48:50:967 ( 1) End onCreate: main
1:48:50:968 (1721) Begin launch(newSingleThreadContext): MyOwnThread
1:48:51:015 ( 1) Begin launch(UI): main
1:49:00:971 (1721) End launch(newSingleThreadContext): MyOwnThread
1:49:00:973 (1720) End launch(Unconfined): kotlinx.coroutines.DefaultExecutor
1:49:00:980 (1724) End launch(CommonPool): ForkJoinPool.commonPool-worker-1
1:49:01:016 ( 1) End launch(UI): main
心得:
Unconfined
在 suspend 之前會是由 calling thread 直接執行,suspend 之後則是用 DefaultExecutor thread 來執行。CommonPool
會是由 common thread pool 裡面的 thread 來執行,suspend 前後被分配的 thread 有可能不同。UI
只能在 main thread 上執行,並且因為是依賴 Android Looper 來實現的,coroutine 會在 onCreate 結束後才被執行到。newSingleThreadContext
會由新產生的 thread 來執行,因爲創建新的 thread 需要一點時間,coroutine 是在 onCreate 結束後才被呼叫到。
這樣的設計主要有兩個優點:一來提供彈性讓使用者根據使用情境決定要使用那些 thread,二來提供擴充性讓使用者可以設計不一樣的 thread dispatching strategy。
如果想要掌握更進階的 coroutine 用法,Coroutine context and dispatchers 是很不錯的使用指南。