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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

fun(n) Java_java程序员的kotlin课(N+2):suspending函数执行编排

發(fā)布時間:2023/12/18 java 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 fun(n) Java_java程序员的kotlin课(N+2):suspending函数执行编排 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

執(zhí)行編排指的是對異步函數(shù)的執(zhí)行順序進行控制,舉個簡單的例子:

需要調用a、b兩個函數(shù),從高效的角度講a、b并行調用有一定是最佳的,但是如果b函數(shù)的輸入依賴a函數(shù)的輸出,那就只能做串行調用。

針對a、b兩個函數(shù)執(zhí)行順序的控制,即本節(jié)要講的執(zhí)行編排,原文中的 Composing Suspending Functions

默認串行執(zhí)行

假設我們有兩個suspending的函數(shù),可能是遠程調用(rpc)。我們假裝這兩個函數(shù)很有用,雖然這兩個函數(shù)只是簡單的delay了一下.

suspend fun doSomethingUsefulOne(): Int {

delay(1000L) // pretend we are doing something useful here

return 13

}

suspend fun doSomethingUsefulTwo(): Int {

delay(1000L) // pretend we are doing something useful here, too

return 29

}

我們如何讓這兩個函數(shù)串行的執(zhí)行呢?依次執(zhí)行doSomethingUsefulOne和doSomethingUsefulTwo,然后計算兩個函數(shù)結果的和,請看下面的代碼(為了計算兩個函數(shù)總的執(zhí)行時間,此處利用了measureTimeMillis函數(shù))

val time = measureTimeMillis {

val one = doSomethingUsefulOne()

val two = doSomethingUsefulTwo()

println("The answer is ${one + two}")

}

println("Completed in $time ms")

執(zhí)行結果如下:

The answer is 42

Completed in 2017 ms

并行執(zhí)行異步操作

如果兩次函數(shù)調用之間沒有有起來關系,我們就可以并行的執(zhí)行兩個函數(shù)了,這樣執(zhí)行起來總的耗時會減少。

從概念上講,async和launch是相似的。他們都可以啟動一個協(xié)程,區(qū)別在于launch返回一個job對象,job對象不攜帶任何結果相關的信息。而async返回一個Deferred類型的對象,和future類似,不過這個是在協(xié)程背景下的,可以通過.await()函數(shù)來獲得結果。而且Deferred也是一個job,一樣可以用來cancel協(xié)程。

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

執(zhí)行速度有兩倍的提升,因為兩個協(xié)程是并行執(zhí)行的。謹記:利用協(xié)程的并行永遠是顯式的。

延遲啟動異步動作

作為一個可選項,在使用async關鍵字啟動協(xié)程的時候,可以傳入?yún)?shù)CoroutineStart.LAZY。在這種模式下,協(xié)程啟動的時機:

await函數(shù)被調用時

start函數(shù)被調用時

val time = measureTimeMillis {

val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }

val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }

// some computation

one.start() // start the first one

two.start() // start the second one

println("The answer is ${one.await() + two.await()}")

}

println("Completed in $time ms")

結果如下:

The answer is 42

Completed in 1017 ms

上面的例子中,兩個協(xié)程并沒有像之前的例子一樣立刻啟動,啟動的控制權交給了編碼者,編碼者可以通過start函數(shù)或者await函數(shù)進行啟動。

但是需要注意的是,如果使用await來觸發(fā)協(xié)程的啟動,上面的例子會變?yōu)榇袌?zhí)行,因為aswit函數(shù)會等待協(xié)程執(zhí)行完畢才向下執(zhí)行接下來的動作。

異步風格的函數(shù)

我們可以通過 async coroutine builder 和顯式的 GlobalScope來把 doSomethingUsefulOne函數(shù)和doSomethingUsefulTwo函數(shù)聲名為異步函數(shù):

// The result type of somethingUsefulOneAsync is Deferred

fun somethingUsefulOneAsync() = GlobalScope.async {

doSomethingUsefulOne()

}

// The result type of somethingUsefulTwoAsync is Deferred

fun somethingUsefulTwoAsync() = GlobalScope.async {

doSomethingUsefulTwo()

}

請注意,上面的xxxAsync函數(shù)并不是suspending函數(shù),他們可以在任何地方被調用。下面的代碼是用來調用上面兩個函數(shù)的代碼:

// note that we don't have `runBlocking` to the right of `main` in this example

fun main() {

val time = measureTimeMillis {

// we can initiate async actions outside of a coroutine

val one = somethingUsefulOneAsync()

val two = somethingUsefulTwoAsync()

// but waiting for a result must involve either suspending or blocking.

// here we use `runBlocking { ... }` to block the main thread while waiting for the result

runBlocking {

println("The answer is ${one.await() + two.await()}")

}

}

println("Completed in $time ms")

}

上面這種編碼風格僅用來展示,因為在其他語言中,這是一種很流行的編碼方式,但是在kotlin中這種編碼風格是強烈不推薦的。

還記得前幾章有講過一個詞結構化并發(fā)或者英文原版structured concurrency,啥意思呢,就是當父協(xié)程取消、異常、關閉時,需要保證子協(xié)程都有被正確的取消,避免資源泄漏。

那么上面的代碼呢?如果val one = somethingUsefulOneAsync()這一行到one.await()這一行發(fā)生任何錯誤,會怎樣?主協(xié)程停止了,報錯了,但是子協(xié)程會一直執(zhí)行。

通過async做結構化異步編程

所以上面的例子,還是需要進行結構化的編碼風格來做:

fun main() = runBlocking {

var a = async { doSomethingUsefulOne() }

var b = async { doSomethingUsefulTwo() }

println(a.await() + b.await())

}

suspend fun doSomethingUsefulOne(): Int {

delay(1024)

return 23

}

suspend fun doSomethingUsefulTwo(): Int {

delay(800)

return 35

}

這種編碼風格,如果main中發(fā)生任何錯誤,所有的子協(xié)程都將被取消。

fun main() = runBlocking {

var a = async { doSomethingUsefulOne() }

var b = async { doSomethingUsefulTwo() }

println(a.await() + b.await())

}

suspend fun doSomethingUsefulOne(): Int {

delay(200)

throw RuntimeException()

return 23

}

suspend fun doSomethingUsefulTwo(): Int {

try {

//永遠都不會被執(zhí)行

delay(Long.MAX_VALUE)

return 35

} finally {

println("cancel.")

}

}

讀者可以自己試一下上面的代碼。

總結

以上是生活随笔為你收集整理的fun(n) Java_java程序员的kotlin课(N+2):suspending函数执行编排的全部內容,希望文章能夠幫你解決所遇到的問題。

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