程式不執行,就只是占據硬碟空間的program
。
一旦啟動,就會產生process
;多次啟動,就會產生多個process
。
process
可以挪用記憶體和各種系統允許它使用的資源,它所擁有的資源會分配給屬下thread
;但每個thread
同一時間只能負責一個工作,稍微有些沈重,所以後來出現了coroutines
;coroutines
是個投機者,可以按照開發者的指令,一會兒和這個thread
借一下,一會兒在那個thread
借一下,自由運用thread
,很適合負責可以切割、零碎的工作。
所以coroutines
也是Kotlin的必考題之一。
「今天來個小測驗,用coroutines
寫倒數計時器吧。」唯心眼看詩憶馬上就要動手開始寫,急忙補充說明。「秒數是使用者可以動態輸入的唷。」
詩憶首先開啟kotlin的coroutines函式庫網頁,查到了artifact id
和最新版本號,加進build.gradle.kts裡。
https://github.com/Kotlin/kotlinx.coroutines/blob/master/README.md#using-in-your-projects
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2")
動態輸入意味著main
函式參數不再空白,詩憶參考講義上的範例在main
函式放進字串陣列參數。此外,為了驗證時間沒有錯誤,她將經過的毫秒數存進timeDelay
變數。
import kotlin.system.measureTimeMillis
import kotlinx.coroutines.*
fun main(args : Array<String>) {
val argTimer = args[0].toInt()
val timeDelay = measureTimeMillis {
delay(argTimer * 1000L)
}
println("$argTimer seconds pass. Time is up!")
println("timeDelay: $timeDelay")
}
還沒開始執行程式,IDE就已經提醒她delay
函式因為有suspend
特性,只能放在coroutines
或是其他suspend
函式。
「學姐,我記得runBlocking
可以直接在當下的thread開一個coroutines
環境,對嗎?」詩憶有點沒把握,寫之前還是想和唯心確認一下。
「對唷。」唯心給了肯定的答覆。
詩憶很放心的加上runBlocking
並加上倒數計時結束印出的字串。
fun main(args : Array<String>) {
val argTimer = args[0].toInt()
runBlocking {
val timeDelay = measureTimeMillis {
println(delayForMe(argTimer))
}
println("timeDelay: $timeDelay")
}
}
suspend fun delayForMe(seconds :Int): String {
delay(seconds * 1000L)
return "$seconds seconds pass. Time is up!"
}
警告消失之後,執行程式還是產生了錯誤Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
。
「學姐,要怎麼在IDE輸入參數啊?」
「平常出現執行功能的地方,不要按太快,清單裡有一個可以修改Run Configuration
的入口,進去後修改Program arguments
就可以了。」
詩憶修改成3之後,重新執行程式。
「嗯⋯⋯如果這樣寫的話,只能一次一個倒數計時,妳試試用async
和await
的組合,放進兩個delayForMe
試試。」唯心建議著。
fun main(args : Array<String>) {
val argTimer = args[0].toInt()
runBlocking {
val timeDelay = measureTimeMillis {
val one = async { delayForMe(argTimer) }
val two = async { delayForMe(argTimer) }
println(one.await() + two.await())
}
println("timeDelay: $timeDelay")
}
}
suspend fun delayForMe(seconds :Int): String {
delay(seconds * 1000L)
return "$seconds seconds pass. Time is up!"
}
「喔喔,這樣兩個倒數計時不會影響到對方!」詩憶驚喜的看著新結果。
「是呀,像現在我另外寫一個把每秒鐘印出的函式,可以直接加入,不用改到妳原本的倒數計時函式。啊,不過文案還是會修改的,要不然看起來會太累贅呢。」
import kotlin.system.measureTimeMillis
import kotlinx.coroutines.*
fun main(args : Array<String>) {
val argTimer = args[0].toInt()
runBlocking {
val timeDelay = measureTimeMillis {
val one = async { delayForMe(argTimer) }
repeat(argTimer) {
val two = async { delayFor1Sec(it + 1) }
println(two.await())
}
println(one.await())
}
println("timeDelay: $timeDelay")
}
}
suspend fun delayForMe(seconds :Int): String {
delay(seconds * 1000L)
return "Time is up!"
}
suspend fun delayFor1Sec(seconds :Int): String {
delay(1000L)
return "$seconds seconds pass."
}