日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android Kotlin 协程async

發布時間:2024/9/30 Android 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android Kotlin 协程async 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/118093646
本文出自【趙彥軍的博客】

往期精彩文章

Android Coroutines Channels

Kotlin實戰指南二十:flow

Kotlin實戰指南十六:Synchronized、Volatile

文章目錄

  • measureTimeMillis 統計一段代碼耗時
  • 使用默認順序
  • 使用 async 并發
  • 惰性啟動的 async
  • 構建async 風格的函數
  • 使用 async 的結構化并發

measureTimeMillis 統計一段代碼耗時

內斂函數 measureTimeMillis{ } 可以很方便的統計一段代碼執行的耗時。

使用:

GlobalScope.launch {val time = measureTimeMillis {delay(1000)Log.d("zyj-", "日志")}Log.d("zyj-", "耗時:$time") }

輸出結果:

D/zyj-: 日志 D/zyj-: 耗時:1010

使用默認順序

定義兩個耗時函數:

suspend fun doSomethingUsefulOne(): Int {delay(1000L) // 假設我們在這里做了一些有用的事return 13 }suspend fun doSomethingUsefulTwo(): Int {delay(1000L) // 假設我們在這里也做了一些有用的事return 29 }

使用默認的順序調用:

val time = measureTimeMillis {val one = doSomethingUsefulOne()val two = doSomethingUsefulTwo()println("The answer is ${one + two}") } println("Completed in $time ms")

它的打印輸出如下:

The answer is 42 Completed in 2017 ms

從輸出結果上看,兩個耗時任務是串行的,總耗時= 耗時函數1 + 耗時函數2

使用 async 并發

如果 doSomethingUsefulOne 與 doSomethingUsefulTwo 之間沒有依賴,并且我們想更快的得到結果,讓它們進行 并發 嗎?這就是async 可以幫助我們的地方。

在概念上,async 就類似于 launch。它啟動了一個單獨的協程與其它所有的協程一起并發的工作。不同之處在于 launch 返回一個 Job 并且不附帶任何結果值,而 async 返回一個 Deferred—— 一個非阻塞 future, 這代表了一個將會在稍后提供結果的 promise。你可以使用 .await()在一個延期的值上得到它的最終結果, 但是 Deferred 也是一個 Job,所以如果需要的話,你可以取消它。

val time = measureTimeMillis {val one = async { doSomethingUsefulOne() }val two = async { doSomethingUsefulTwo() }println("The answer is ${one.await() + two.await()}") } println("Completed in $time ms")

它的打印輸出如下:

The answer is 42 Completed in 1017 ms

這里快了兩倍,因為兩個協程并發執行。 請注意,使用協程進行并發總是顯式的。

惰性啟動的 async

可選的,async 可以通過將 start 參數設置為 CoroutineStart.LAZY 而變為惰性的。 在這個模式下,只有結果通過 await 獲取的時候協程才會啟動,或者在 Job 的 start函數調用的時候。運行下面的示例:

val time = measureTimeMillis {val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }// 執行一些計算one.start() // 啟動第一個two.start() // 啟動第二個println("The answer is ${one.await() + two.await()}") } println("Completed in $time ms")

它的打印輸出如下:

The answer is 42 Completed in 1017 ms

因此,在先前的例子中這里定義的兩個協程沒有執行,但是控制權在于程序員準確的在開始執行時調用 start。我們首先 調用 one,然后調用 two,接下來等待這個協程執行完畢。

注意,如果我們只是在 println 中調用 await,而沒有在單獨的協程中調用 start,這將會導致順序行為,直到 await 啟動該協程 執行并等待至它結束,這并不是惰性的預期用例。 在計算一個值涉及掛起函數時,這個 async(start = CoroutineStart.LAZY)的用例用于替代標準庫中的 lazy 函數。

構建async 風格的函數

我們可以定義異步風格的函數來 異步 的調用 doSomethingUsefulOne 和 doSomethingUsefulTwo 并使用 async 協程建造器并帶有一個顯式的 GlobalScope 引用。 我們給這樣的函數的名稱中加上“……Async”后綴來突出表明:事實上,它們只做異步計算并且需要使用延期的值來獲得結果。

// somethingUsefulOneAsync 函數的返回值類型是 Deferred<Int> fun somethingUsefulOneAsync() = GlobalScope.async {doSomethingUsefulOne() }// somethingUsefulTwoAsync 函數的返回值類型是 Deferred<Int> fun somethingUsefulTwoAsync() = GlobalScope.async {doSomethingUsefulTwo() }

使用

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 我們可以在協程外面啟動異步執行val one = somethingUsefulOneAsync()val two = somethingUsefulTwoAsync()// 但是等待結果必須調用其它的掛起或者阻塞// 當我們等待結果的時候,這里我們使用 `GlobalScope.launch{ }` 來阻塞主線程GlobalScope.launch {println("The- answer is ${one.await()} ${two.await()}")}} }

這種帶有異步函數的編程風格僅供參考,因為這在其它編程語言中是一種受歡迎的風格。在 Kotlin 的協程中使用這種風格是強烈不推薦的, 原因如下所述。

考慮一下如果 val one = somethingUsefulOneAsync() 這一行和 one.await() 表達式這里在代碼中有邏輯錯誤, 并且程序拋出了異常以及程序在操作的過程中中止,將會發生什么。 通常情況下,一個全局的異常處理者會捕獲這個異常,將異常打印成日記并報告給開發者,但是反之該程序將會繼續執行其它操作。但是這里我們的 somethingUsefulOneAsync仍然在后臺執行, 盡管如此,啟動它的那次操作也會被終止。這個程序將不會進行結構化并發,如下一小節所示。

使用 async 的結構化并發

讓我們使用使用 async 的并發這一小節的例子并且提取出一個函數并發的調用 doSomethingUsefulOne 與 doSomethingUsefulTwo 并且返回它們兩個的結果之和。 由于 async 被定義為了 CoroutineScope上的擴展,我們需要將它寫在作用域內,并且這是 coroutineScope 函數所提供的:

suspend fun concurrentSum(): Int = coroutineScope {val one = async { doSomethingUsefulOne() }val two = async { doSomethingUsefulTwo() }one.await() + two.await() }

這種情況下,如果在 concurrentSum 函數內部發生了錯誤,并且它拋出了一個異常, 所有在作用域中啟動的協程都會被取消。

val time = measureTimeMillis {println("The answer is ${concurrentSum()}") } println("Completed in $time ms")

從上面的 main 函數的輸出可以看出,我們仍然可以同時執行這兩個操作:

The answer is 42 Completed in 1017 ms

取消始終通過協程的層次結構來進行傳遞:

import kotlinx.coroutines.*fun main() = runBlocking<Unit> {try {failedConcurrentSum()} catch(e: ArithmeticException) {println("Computation failed with ArithmeticException")} }suspend fun failedConcurrentSum(): Int = coroutineScope {val one = async<Int> { try {delay(Long.MAX_VALUE) // 模擬一個長時間的運算42} finally {println("First child was cancelled")}}val two = async<Int> { println("Second child throws an exception")throw ArithmeticException()}one.await() + two.await() }

請注意,如果其中一個子協程(即 two)失敗,第一個 async 以及等待中的父協程都會被取消:

Second child throws an exception First child was cancelled Computation failed with ArithmeticException 與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的Android Kotlin 协程async的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。