假設(shè)我們在不同的地?定義了兩個進(jìn)?某種調(diào)?遠(yuǎn)程服務(wù)或者進(jìn)?計算的掛起函數(shù)。我們只假設(shè)它們都是有?的,但是實(shí)際上它們在這個?例中只是為了該?的?延遲了?秒鐘:
成都創(chuàng)新互聯(lián)公司自2013年創(chuàng)立以來,先為饒河等服務(wù)建站,饒河等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為饒河企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。suspend fun doSomethingUsefulOne(): Int { delay(1000L) // 假設(shè)我們在這?做了?些有?的事 return 13 } suspend fun doSomethingUsefulTwo(): Int { delay(1000L) // 假設(shè)我們在這?也做了?些有?的事 return 29 }如果需要按 順序 調(diào)?它們,我們接下來會做什么??先調(diào)? doSomethingUsefulOne 接下來 調(diào) ? doSomethingUsefulTwo ,并且計算它們結(jié)果的和嗎?實(shí)際上,如果我們要根據(jù)第?個函數(shù)的結(jié) 果來決定是否我們需要調(diào)?第?個函數(shù)或者決定如何調(diào)?它時,我們就會這樣做。 我們使?普通的順序來進(jìn)?調(diào)?,因?yàn)檫@些代碼是運(yùn)?在協(xié)程中的,只要像常規(guī)的代碼?樣 順序 都是 默認(rèn)的。下?的?例展?了測量執(zhí)?兩個掛起函數(shù)所需要的總時間:
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使用async并發(fā)
如果 doSomethingUsefulOne 與 doSomethingUsefulTwo 之間沒有依賴,并且我們想更快的得 到結(jié)果,讓它們進(jìn)? 并發(fā) 嗎?這就是 async 可以幫助我們的地?。 在概念上,async 就類似于 launch。它啟動了?個單獨(dú)的協(xié)程,這是?個輕量級的線程并與其它所有的 協(xié)程?起并發(fā)的?作。不同之處在于 launch 返回?個 Job 并且不附帶任何結(jié)果值,? async 返回 ?個 Deferred??個輕量級的?阻塞 future,這代表了?個將會在稍后提供結(jié)果的 promise。你可 以使? .await() 在?個延期的值上得到它的最終結(jié)果,但是 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這?快了兩倍,因?yàn)閮蓚€協(xié)程并發(fā)執(zhí)?。請注意,使?協(xié)程進(jìn)?并發(fā)總是顯式的。
惰性啟動的 async
可選的,async 可以通過將 start 參數(shù)設(shè)置為 CoroutineStart.LAZY ?變?yōu)槎栊缘?。在這個模式下, 只有結(jié)果通過 await 獲取的時候協(xié)程才會啟動,或者在 Job 的 start 函數(shù)調(diào)?的時候。運(yùn)?下?的?例:
val time = measureTimeMillis { val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() } val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() } // 執(zhí)??些計算 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因此,在先前的例?中這?定義的兩個協(xié)程沒有執(zhí)?,但是控制權(quán)在于程序員準(zhǔn)確的在開始執(zhí)?時調(diào)? start。我們?先 調(diào)? one ,然后調(diào)? two ,接下來等待這個協(xié)程執(zhí)?完畢。 注意,如果我們只是在 println 中調(diào)? await,?沒有在單獨(dú)的協(xié)程中調(diào)? start,這將會導(dǎo)致順序? 為,直到 await 啟動該協(xié)程 執(zhí)?并等待?它結(jié)束,這并不是惰性的預(yù)期?例。在計算?個值涉及掛起函 數(shù)時,這個 async(start = CoroutineStart.LAZY) 的?例?于替代標(biāo)準(zhǔn)庫中的 lazy 函數(shù)。
async風(fēng)格的函數(shù)
我們可以定義異步?格的函數(shù)來 異步 的調(diào)? doSomethingUsefulOne 和 doSomethingUsefulTwo 并使? async 協(xié)程建造器并帶有?個顯式的 GlobalScope 引?。我們給 這樣的函數(shù)的名稱中加上“……Async”后綴來突出表明:事實(shí)上,它們只做異步計算并且需要使?延期 的值來獲得結(jié)果。
// somethingUsefulOneAsync 函數(shù)的返回值類型是 Deferred<Int> fun somethingUsefulOneAsync() = GlobalScope.async { doSomethingUsefulOne() } // somethingUsefulTwoAsync 函數(shù)的返回值類型是 Deferred<Int> fun somethingUsefulTwoAsync() = GlobalScope.async { doSomethingUsefulTwo() }注意,這些 xxxAsync 函數(shù)不是 掛起 函數(shù)。它們可以在任何地?使?。然?,它們總是在調(diào)?它們的 代碼中意味著異步(這?的意思是 并發(fā) )執(zhí)?。 下?的例?展?了它們在協(xié)程的外?是如何使?的:
// 注意,在這個?例中我們在 `main` 函數(shù)的右邊沒有加上 `runBlocking` fun main() { val time = measureTimeMillis { // 我們可以在協(xié)程外?啟動異步執(zhí)? val one = somethingUsefulOneAsync() val two = somethingUsefulTwoAsync() // 但是等待結(jié)果必須調(diào)?其它的掛起或者阻塞 // 當(dāng)我們等待結(jié)果的時候,這?我們使? `runBlocking { …… }` 來阻塞主線程 runBlocking { println("The answer is ${one.await() + two.await()}") } } println("Completed in $time ms") }這種帶有異步函數(shù)的編程?格僅供參考,因?yàn)檫@在其它編程語?中是?種受歡迎的?格。在 Kotlin 的協(xié)程中使?這種?格是強(qiáng)烈不推薦的,原因如下所述。
考慮?下如果 val one = somethingUsefulOneAsync() 這??和 one.await() 表達(dá)式這? 在代碼中有邏輯錯誤,并且程序拋出了異常以及程序在操作的過程中中?,將會發(fā)?什么。通常情況 下,?個全局的異常處理者會捕獲這個異常,將異常打印成?記并報告給開發(fā)者,但是反之該程序?qū)?繼續(xù)執(zhí)?其它操作。但是這?我們的 somethingUsefulOneAsync 仍然在后臺執(zhí)?,盡管如此,啟 動它的那次操作也會被終?。這個程序?qū)⒉粫M(jìn)?結(jié)構(gòu)化并發(fā),如下??節(jié)所?。
使用async的結(jié)構(gòu)化并發(fā)
讓我們使?使? async 的并發(fā)這??節(jié)的例?并且提取出?個函數(shù)并發(fā)的調(diào)? doSomethingUsefulOne 與 doSomethingUsefulTwo 并且返回它們兩個的結(jié)果之和。由于 async 被定義為了 CoroutineScope 上的擴(kuò)展,我們需要將它寫在作?域內(nèi),并且這是 coroutineScope 函數(shù)所提供的:
suspend fun concurrentSum(): Int = coroutineScope {
val one= async { doSomethingUsefulOne() }
val two= async { doSomethingUsefulTwo() }
one.await() + two.await()
}
這種情況下,如果在 concurrentSum 函數(shù)內(nèi)部發(fā)?了錯誤,并且它拋出了?個異常,所有在作?域 中啟動的協(xié)程都會被取消。
val time = measureTimeMillis {
println("The answer is ${concurrentSum()}")
}
println("Completed in $time ms")
從上?的 main 函數(shù)的輸出可以看出,我們?nèi)匀豢梢酝瑫r執(zhí)?這兩個操作:
The answer is 42 Completed in 1017 ms取消始終通過協(xié)程的層次結(jié)構(gòu)來進(jìn)?傳遞:
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) // 模擬?個?時間的運(yùn)算 42 } finally { println("First child was cancelled") } } val two = async<Int> { println("Second child throws an exception") throw ArithmeticException() } one.await() + two.await() }請注意,如果其中?個?協(xié)程(即 two )失敗,第?個 async 以及等待中的?協(xié)程都會被取消:
Second child throws an exception First child was cancelled Computation failed with ArithmeticException
當(dāng)前名稱:kotlin協(xié)程——>組合掛起函數(shù)-創(chuàng)新互聯(lián)
網(wǎng)站路徑:http://jinyejixie.com/article26/hgpjg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開發(fā)、ChatGPT、品牌網(wǎng)站設(shè)計、營銷型網(wǎng)站建設(shè)、全網(wǎng)營銷推廣、自適應(yīng)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容