<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                **目錄** [TOC] ## 協程基礎 這一部分包括基礎的協程概念。 ### 你的第一個協程程序 運行以下代碼: ```kotlin import kotlinx.coroutines.* fun main() { GlobalScope.launch { // 在后臺啟動一個新的協程并繼續 delay(1000L) // 非阻塞的等待 1 秒鐘(默認時間單位是毫秒) println("World!") // 在延遲后打印輸出 } println("Hello,") // 協程已在等待時主線程還在繼續 Thread.sleep(2000L) // 阻塞主線程 2 秒鐘來保證 JVM 存活 } ``` > 可以在[這里](https://github.com/hltj/kotlinx.coroutines-cn/blob/master/kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt)獲取完整代碼。 代碼運行的結果: ```text Hello, World! ``` 本質上,協程是輕量級的線程。它們在某些 [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html) 上下文中與 [launch](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html) _協程構建器_ 一起啟動。這里我們在 [GlobalScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html) 中啟動了一個新的協程,這意味著新協程的生命周期只受整個應用程序的生命周期限制。 可以將`GlobalScope.launch { …… }` 替換為 `thread { …… }`,將 `delay(……)` 替換為 `Thread.sleep(……)` 達到同樣目的。 嘗試一下。 如果你首先將 `GlobalScope.launch` 替換為 `thread`,編譯器會報以下錯誤: ``` Error: Kotlin: Suspend functions are only allowed to be called from a coroutine or another suspend function ``` 這是因為 [delay](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html) 是一個特殊的 _掛起函數_ ,它不會造成線程阻塞,但是會 _掛起_協程,并且只能在協程中使用。 ### 橋接阻塞與非阻塞的世界 第一個示例在同一段代碼中混用了 _非阻塞的_ `delay(……)` 與 _阻塞的_ `Thread.sleep(……)`。這容易讓我們記混哪個是阻塞的、哪個是非阻塞的。讓我們顯式使用 [runBlocking](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html) 協程構建器來阻塞: ```kotlin import kotlinx.coroutines.* fun main() { GlobalScope.launch { // 在后臺啟動一個新的協程并繼續 delay(1000L) println("World!") } println("Hello,") // 主線程中的代碼會立即執行 runBlocking { // 但是這個表達式阻塞了主線程 delay(2000L) // ……我們延遲 2 秒來保證 JVM 的存活 } } ``` > 可以在[這里](https://github.com/hltj/kotlinx.coroutines-cn/blob/master/kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt)獲取完整代碼。 結果是相似的,但是這些代碼只使用了非阻塞的函數 [delay](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html)。調用了 `runBlocking` 的主線程會一直 _阻塞_ 直到 `runBlocking` 內部的協程執行完畢。 這個示例可以使用更合乎慣用法的方式重寫,使用 `runBlocking` 來包裝main 函數的執行: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking<Unit> { // 開始執行主協程 GlobalScope.launch { // 在后臺啟動一個新的協程并繼續 delay(1000L) println("World!") } println("Hello,") // 主協程在這里會立即執行 delay(2000L) // 延遲 2 秒來保證 JVM 存活 } ``` > 可以在[這里](https://github.com/hltj/kotlinx.coroutines-cn/blob/master/kotlinx-coroutines-core/jvm/test/guide/example-basic-02b.kt)獲取完整代碼。 這里的 `runBlocking<Unit> { …… }` 作為用來啟動頂層主協程的適配器。我們顯式指定了其返回類型 `Unit`,因為在 Kotlin 中 `main` 函數必須返回 `Unit` 類型。 這也是為掛起函數編寫單元測試的一種方式: ```kotlin class MyTest { @Test fun testMySuspendingFunction() = runBlocking<Unit> { // 這里我們可以使用任何喜歡的斷言風格來使用掛起函數 } } ``` ### 等待一個作業 延遲一段時間來等待另一個協程運行并不是一個好的選擇。讓我們顯式(以非阻塞方式)等待所啟動的后臺 [Job] 執行結束: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { //sampleStart val job = GlobalScope.launch { // 啟動一個新協程并保持對這個作業的引用 delay(1000L) println("World!") } println("Hello,") job.join() // 等待直到子協程執行結束 //sampleEnd } ``` > 可以在[這里](https://github.com/hltj/kotlinx.coroutines-cn/blob/master/kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt)獲取完整代碼。 現在,結果仍然相同,但是主協程與后臺作業的持續時間沒有任何關系了。好多了。 ### 結構化的并發 協程的實際使用還有一些需要改進的地方。當我們使用 `GlobalScope.launch` 時,我們會創建一個頂層協程。雖然它很輕量,但它運行時仍會消耗一些內存資源。如果我們忘記保持對新啟動的協程的引用,它還會繼續運行。如果協程中的代碼掛起了會怎么樣(例如,我們錯誤地延遲了太長時間),如果我們啟動了太多的協程并導致內存不足會怎么樣?必須手動保持對所有已啟動協程的引用并 [join](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html) 之很容易出錯。 有一個更好的解決辦法。我們可以在代碼中使用結構化并發。我們可以在執行操作所在的指定作用域內啟動協程,而不是像通常使用線程(線程總是全局的)那樣在 [GlobalScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html) 中啟動。 在我們的示例中,我們使用 [runBlocking](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html) 協程構建器將 `main` 函數轉換為協程。包括 `runBlocking` 在內的每個協程構建器都將 [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html) 的實例添加到其代碼塊所在的作用域中。我們可以在這個作用域中啟動協程而無需顯式 `join` 之,因為外部協程(示例中的 `runBlocking`)直到在其作用域中啟動的所有協程都執行完畢后才會結束。因此,可以將我們的示例簡化為: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { // this: CoroutineScope launch { // 在 runBlocking 作用域中啟動一個新協程 delay(1000L) println("World!") } println("Hello,") } ``` > 可以在[這里](https://github.com/hltj/kotlinx.coroutines-cn/blob/master/kotlinx-coroutines-core/jvm/test/guide/example-basic-03s.kt)獲取完整代碼。 ### 作用域構建器 除了由不同的構建器提供協程作用域之外,還可以使用[coroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html) 構建器聲明自己的作用域。它會創建一個協程作用域并且在所有已啟動子協程執行完畢之前不會結束。[runBlocking](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html) 與 [coroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html) 的主要區別在于后者在等待所有子協程執行完畢時不會阻塞當前線程。 ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { // this: CoroutineScope launch { delay(200L) println("Task from runBlocking") } coroutineScope { // 創建一個協程作用域 launch { delay(500L) println("Task from nested launch") } delay(100L) println("Task from coroutine scope") // 這一行會在內嵌 launch 之前輸出 } println("Coroutine scope is over") // 這一行在內嵌 launch 執行完畢后才輸出 } ``` > 可以在[這里](https://github.com/hltj/kotlinx.coroutines-cn/blob/master/kotlinx-coroutines-core/jvm/test/guide/example-basic-04.kt)獲取完整代碼。 ### 提取函數重構 我們來將 `launch { …… }` 內部的代碼塊提取到獨立的函數中。當你對這段代碼執行“提取函數”重構時,你會得到一個帶有 `suspend` 修飾符的新函數。那是你的第一個*掛起函數*。在協程內部可以像普通函數一樣使用掛起函數,不過其額外特性是,同樣可以使用其他掛起函數(如本例中的 `delay`)來*掛起*協程的執行。 ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { launch { doWorld() } println("Hello,") } // 這是你的第一個掛起函數 suspend fun doWorld() { delay(1000L) println("World!") } ``` > 可以在[這里](https://github.com/hltj/kotlinx.coroutines-cn/blob/master/kotlinx-coroutines-core/jvm/test/guide/example-basic-05.kt)獲取完整代碼。 但是如果提取出的函數包含一個在當前作用域中調用的協程構建器的話,該怎么辦?在這種情況下,所提取函數上只有 `suspend` 修飾符是不夠的。為 `CoroutineScope` 寫一個 `doWorld` 擴展方法是其中一種解決方案,但這可能并非總是適用,因為它并沒有使 API 更加清晰。慣用的解決方案是要么顯式將 `CoroutineScope` 作為包含該函數的類的一個字段,要么當外部類實現了 `CoroutineScope` 時隱式取得。作為最后的手段,可以使用 [CoroutineScope(coroutineContext)](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html),不過這種方法結構上不安全,因為你不能再控制該方法執行的作用域。只有私有 API 才能使用這個構建器。 ### 協程很輕量 運行以下代碼: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { repeat(100_000) { // 啟動大量的協程 launch { delay(1000L) print(".") } } } ``` > 可以在[這里](https://github.com/hltj/kotlinx.coroutines-cn/blob/master/kotlinx-coroutines-core/jvm/test/guide/example-basic-06.kt)獲取完整代碼。 它啟動了 10 萬個協程,并且在一秒鐘后,每個協程都輸出一個點。現在,嘗試使用線程來實現。會發生什么?(很可能你的代碼會產生某種內存不足的錯誤) ### 全局協程像守護線程 以下代碼在 [GlobalScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html)中啟動了一個長期運行的協程,該協程每秒輸出“I'm sleeping”兩次,之后在主函數中延遲一段時間后返回。 ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { //sampleStart GlobalScope.launch { repeat(1000) { i -> println("I'm sleeping $i ...") delay(500L) } } delay(1300L) // 在延遲后退出 //sampleEnd } ``` > 可以在[這里](https://github.com/hltj/kotlinx.coroutines-cn/blob/master/kotlinx-coroutines-core/jvm/test/guide/example-basic-07.kt)獲取完整代碼。 你可以運行這個程序并看到它輸出了以下三行后終止: ```text I'm sleeping 0 ... I'm sleeping 1 ... I'm sleeping 2 ... ``` 在 [GlobalScope] 中啟動的活動協程并不會使進程保活。它們就像守護線程。 [launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html [CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html [GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html [delay]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html [runBlocking]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html [Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html [Job.join]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html [coroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html [CoroutineScope()]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看