iT邦幫忙

2021 iThome 鐵人賽

DAY 26
1
Software Development

溫柔學姐的Kotlin補課/教學系列 第 26

有限資源分配:coroutines 非同步 suspend async

  • 分享至 

  • xImage
  •  

程式不執行,就只是占據硬碟空間的program

一旦啟動,就會產生process;多次啟動,就會產生多個process

process可以挪用記憶體和各種系統允許它使用的資源,它所擁有的資源會分配給屬下thread;但每個thread同一時間只能負責一個工作,稍微有些沈重,所以後來出現了coroutinescoroutines是個投機者,可以按照開發者的指令,一會兒和這個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函式。

圖1

「學姐,我記得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就可以了。」

圖2

圖3

詩憶修改成3之後,重新執行程式。

圖4

「嗯⋯⋯如果這樣寫的話,只能一次一個倒數計時,妳試試用asyncawait的組合,放進兩個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!"
}

圖5

「喔喔,這樣兩個倒數計時不會影響到對方!」詩憶驚喜的看著新結果。

「是呀,像現在我另外寫一個把每秒鐘印出的函式,可以直接加入,不用改到妳原本的倒數計時函式。啊,不過文案還是會修改的,要不然看起來會太累贅呢。」

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."
}

圖6


上一篇
給別人前先包裝:套件、匯入、存取修飾詞 Packages, imports and Visibility modifiers
下一篇
框架在手,工作我有:MockK的簡介?真的只是簡介⋯⋯
系列文
溫柔學姐的Kotlin補課/教學31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言