
假設(shè)我們在不同的地?定義了兩個(gè)進(jìn)?某種調(diào)?遠(yuǎn)程服務(wù)或者進(jìn)?計(jì)算的掛起函數(shù)。我們只假設(shè)它們都是有?的,但是實(shí)際上它們在這個(gè)?例中只是為了該?的?延遲了?秒鐘:

如果需要按 順序 調(diào)?它們,我們接下來會(huì)做什么??先調(diào)? doSomethingUsefulOne 接下來 調(diào) ? doSomethingUsefulTwo ,并且計(jì)算它們結(jié)果的和嗎?實(shí)際上,如果我們要根據(jù)第?個(gè)函數(shù)的結(jié) 果來決定是否我們需要調(diào)?第?個(gè)函數(shù)或者決定如何調(diào)?它時(shí),我們就會(huì)這樣做。 我們使?普通的順序來進(jìn)?調(diào)?,因?yàn)檫@些代碼是運(yùn)?在協(xié)程中的,只要像常規(guī)的代碼?樣 順序 都是 默認(rèn)的。下?的?例展?了測量執(zhí)?兩個(gè)掛起函數(shù)所需要的總時(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òng)了?個(gè)單獨(dú)的協(xié)程,這是?個(gè)輕量級(jí)的線程并與其它所有的 協(xié)程?起并發(fā)的?作。不同之處在于 launch 返回?個(gè) Job 并且不附帶任何結(jié)果值,? async 返回 ?個(gè) Deferred??個(gè)輕量級(jí)的?阻塞 future,這代表了?個(gè)將會(huì)在稍后提供結(jié)果的 promise。你可 以使? .await() 在?個(gè)延期的值上得到它的最終結(jié)果,但是 Deferred 也是?個(gè) 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)閮蓚€(gè)協(xié)程并發(fā)執(zhí)?。請注意,使?協(xié)程進(jìn)?并發(fā)總是顯式的。
惰性啟動(dòng)的 async
可選的,async 可以通過將 start 參數(shù)設(shè)置為 CoroutineStart.LAZY ?變?yōu)槎栊缘摹T谶@個(gè)模式下, 只有結(jié)果通過 await 獲取的時(shí)候協(xié)程才會(huì)啟動(dòng),或者在 Job 的 start 函數(shù)調(diào)?的時(shí)候。運(yùn)?下?的?例:
val time = measureTimeMillis { val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() } val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() } // 執(zhí)??些計(jì)算 one.start() // 啟動(dòng)第?個(gè) two.start() // 啟動(dòng)第?個(gè) println("The answer is ${one.await() + two.await()}") } println("Completed in $time ms")它的打印輸出如下:
The answer is 42 Completed in 1017 ms因此,在先前的例?中這?定義的兩個(gè)協(xié)程沒有執(zhí)?,但是控制權(quán)在于程序員準(zhǔn)確的在開始執(zhí)?時(shí)調(diào)? start。我們?先 調(diào)? one ,然后調(diào)? two ,接下來等待這個(gè)協(xié)程執(zhí)?完畢。 注意,如果我們只是在 println 中調(diào)? await,?沒有在單獨(dú)的協(xié)程中調(diào)? start,這將會(huì)導(dǎo)致順序? 為,直到 await 啟動(dòng)該協(xié)程 執(zhí)?并等待?它結(jié)束,這并不是惰性的預(yù)期?例。在計(jì)算?個(gè)值涉及掛起函 數(shù)時(shí),這個(gè) async(start = CoroutineStart.LAZY) 的?例?于替代標(biāo)準(zhǔn)庫中的 lazy 函數(shù)。
async風(fēng)格的函數(shù)
我們可以定義異步?格的函數(shù)來 異步 的調(diào)? doSomethingUsefulOne 和 doSomethingUsefulTwo 并使? async 協(xié)程建造器并帶有?個(gè)顯式的 GlobalScope 引?。我們給 這樣的函數(shù)的名稱中加上“……Async”后綴來突出表明:事實(shí)上,它們只做異步計(jì)算并且需要使?延期 的值來獲得結(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é)程的外?是如何使?的:
// 注意,在這個(gè)?例中我們在 `main` 函數(shù)的右邊沒有加上 `runBlocking` fun main() { val time = measureTimeMillis { // 我們可以在協(xié)程外?啟動(dòng)異步執(zhí)? val one = somethingUsefulOneAsync() val two = somethingUsefulTwoAsync() // 但是等待結(jié)果必須調(diào)?其它的掛起或者阻塞 // 當(dāng)我們等待結(jié)果的時(shí)候,這?我們使? `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á)式這? 在代碼中有邏輯錯(cuò)誤,并且程序拋出了異常以及程序在操作的過程中中?,將會(huì)發(fā)?什么。通常情況 下,?個(gè)全局的異常處理者會(huì)捕獲這個(gè)異常,將異常打印成?記并報(bào)告給開發(fā)者,但是反之該程序?qū)?huì) 繼續(xù)執(zhí)?其它操作。但是這?我們的 somethingUsefulOneAsync 仍然在后臺(tái)執(zhí)?,盡管如此,啟 動(dòng)它的那次操作也會(huì)被終?。這個(gè)程序?qū)⒉粫?huì)進(jìn)?結(jié)構(gòu)化并發(fā),如下??節(jié)所?。
使用async的結(jié)構(gòu)化并發(fā)
讓我們使?使? async 的并發(fā)這??節(jié)的例?并且提取出?個(gè)函數(shù)并發(fā)的調(diào)? doSomethingUsefulOne 與 doSomethingUsefulTwo 并且返回它們兩個(gè)的結(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ā)?了錯(cuò)誤,并且它拋出了?個(gè)異常,所有在作?域 中啟動(dòng)的協(xié)程都會(huì)被取消。
val time = measureTimeMillis {
println("The answer is ${concurrentSum()}")
}
println("Completed in $time ms")從上?的 main 函數(shù)的輸出可以看出,我們?nèi)匀豢梢酝瑫r(shí)執(zhí)?這兩個(gè)操作:
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) // 模擬?個(gè)?時(shí)間的運(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() }請注意,如果其中?個(gè)?協(xié)程(即 two )失敗,第?個(gè) async 以及等待中的?協(xié)程都會(huì)被取消:
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://chinadenli.net/article26/hgpjg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開發(fā)、ChatGPT、品牌網(wǎng)站設(shè)計(jì)、營銷型網(wǎng)站建設(shè)、全網(wǎng)營銷推廣、自適應(yīng)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容