【翻譯】kotlin協(xié)程核心庫(kù)文檔(一)—— 協(xié)程基礎(chǔ)

github原文地址

原創(chuàng)翻譯,轉(zhuǎn)載請(qǐng)保留或注明出處:http://www.itdecent.cn/p/7497bce754eb

協(xié)程基礎(chǔ)


本小節(jié)涵蓋了協(xié)程的基礎(chǔ)概念

第一個(gè)協(xié)程

運(yùn)行以下代碼:

fun main(args: Array<String>) {
    launch { // launch new coroutine in background and continue
        delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
        println("World!") // print after delay
    }
    println("Hello,") // main thread continues while coroutine is delayed
    Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}

獲取完整代碼 here

運(yùn)行結(jié)果:

Hello,
World!

實(shí)質(zhì)上,協(xié)程是輕量級(jí)的線程。它們使用 “l(fā)aunch” 協(xié)程構(gòu)建器啟動(dòng) ,你也可以通過(guò)如下方式獲得同樣的結(jié)果:替換 launch { ... }thread { ... }, 替換delay(...)Thread.sleep(...)。

連接阻塞、非阻塞的世界

第一個(gè)示例混合了非阻塞的 delay(...) 與 阻塞的 Thread.sleep(...) 在同一塊代碼中。這很容易讓人迷惑哪一處是阻塞的哪一處不是。我們可以通過(guò)使用 runBlocking 協(xié)程構(gòu)建器來(lái)明確阻塞:

fun main(args: Array<String>) {
    launch { // launch new coroutine in background and continue
        delay(1000L)
        println("World!")
    }
    println("Hello,") // main thread continues here immediately
    runBlocking { // but this expression blocks the main thread
        delay(2000L) // ... while we delay for 2 seconds to keep JVM alive
    }
}

獲取完整代碼 here

結(jié)果是相同的,但是這段代碼使用了非阻塞的delay。調(diào)用runBlocking的主線程阻塞了,直到內(nèi)部協(xié)程runBlocking完成。

這個(gè)示例同樣可以用一種更通順的方式改寫(xiě):使用runBlocking來(lái)封裝主函數(shù)的執(zhí)行:

fun main(args: Array<String>) = runBlocking<Unit> { // start main coroutine
    launch { // launch new coroutine in background and continue
        delay(1000L)
        println("World!")
    }
    println("Hello,") // main coroutine continues here immediately
    delay(2000L) // delaying for 2 seconds to keep JVM alive
}

獲取完整代碼 here

這里runBlocking<Unit> { ... }作為一個(gè)適配器,用來(lái)啟動(dòng)頂層主協(xié)程。 我們明確地指定它的返回類型為Unit,因?yàn)橐粋€(gè)格式良好的Kotlin主函數(shù)必須返回 Unit 。

這同樣也是為掛起函數(shù)編寫(xiě)單元測(cè)試的一種方式:

class MyTest {
    @Test
    fun testMySuspendingFunction() = runBlocking<Unit> {
        // here we can use suspending functions using any assertion style that we like
    }
}

等待一個(gè)任務(wù)

當(dāng)另一個(gè)協(xié)程正在工作時(shí),延遲一段時(shí)間并不是一個(gè)好的方式。我們可以通過(guò)明確地方式等待(以非阻塞的方式),直到我們之前啟動(dòng)的后臺(tái)任務(wù)完成:

fun main(args: Array<String>) = runBlocking<Unit> {
    val job = launch { // launch new coroutine and keep a reference to its Job
        delay(1000L)
        println("World!")
    }
    println("Hello,")
    job.join() // wait until child coroutine completes
}

獲取完整代碼 here

現(xiàn)在結(jié)果是同樣的,但是主協(xié)程的代碼不以任何方式與后臺(tái)任務(wù)的執(zhí)行時(shí)間相關(guān)聯(lián)。

提取函數(shù)進(jìn)行重構(gòu)

我們可以提取launch { ... }中的代碼塊到另一個(gè)分離的函數(shù)中。當(dāng)你對(duì)這段代碼進(jìn)行“提取函數(shù)”重構(gòu)時(shí),你會(huì)得到一個(gè)帶有 suspend 修飾符的新函數(shù)。這是你的第一個(gè)掛起函數(shù)。掛起函數(shù)可以像普通函數(shù)一樣在協(xié)程中使用,但他們的附加功能是,他們可以反過(guò)來(lái)使用其他掛起函數(shù)。類似這個(gè)示例中的delay,它掛起了一個(gè)協(xié)程的執(zhí)行過(guò)程。

fun main(args: Array<String>) = runBlocking<Unit> {
    val job = launch { doWorld() }
    println("Hello,")
    job.join()
}

// this is your first suspending function
suspend fun doWorld() {
    delay(1000L)
    println("World!")
}

獲取完整代碼 here

協(xié)程是輕量的

執(zhí)行以下代碼:

fun main(args: Array<String>) = runBlocking<Unit> {
    val jobs = List(100_000) { // launch a lot of coroutines and list their jobs
        launch {
            delay(1000L)
            print(".")
        }
    }
    jobs.forEach { it.join() } // wait for all jobs to complete
}

獲取完整代碼 here

它啟動(dòng)了10萬(wàn)個(gè)協(xié)程,并在一秒后,每個(gè)協(xié)程打印了一個(gè)“.”。騷年,你敢用線程做這樣的事么?(很可能你的代碼會(huì)產(chǎn)生一些內(nèi)存溢出的錯(cuò)誤)。

協(xié)程類似守護(hù)線程

下面的代碼啟動(dòng)了一個(gè)長(zhǎng)時(shí)間運(yùn)行的協(xié)程,它每秒打印兩次“I'm sleeping”,在一段延遲后從主函數(shù)返回:

fun main(args: Array<String>) = runBlocking<Unit> {
    launch {
        repeat(1000) { i ->
            println("I'm sleeping $i ...")
            delay(500L)
        }
    }
    delay(1300L) // just quit after delay
}

獲取完整代碼 here

你可以運(yùn)行并看到它打印了三行然后終止:

I'm sleeping 0 ...
I'm sleeping 1 ...
I'm sleeping 2 ...

激活的協(xié)程并不會(huì)使進(jìn)程保持活躍狀態(tài),它們就像守護(hù)線程一樣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容