select 表達(dá)式可以同時(shí)等待多個(gè)掛起函數(shù),并 選擇 第?個(gè)可?的。
創(chuàng)新互聯(lián)建站主要從事網(wǎng)站制作、成都網(wǎng)站制作、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)梓潼,十年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):028-86922220在通道中 select
我們現(xiàn)在有兩個(gè)字符串?產(chǎn)者:fizz 和 buzz 。其中 fizz 每 300 毫秒?成?個(gè)“Fizz”字符串:
fun CoroutineScope.fizz() = produce接著 buzz 每 500 毫秒?成?個(gè)“Buzz!”字符串:
fun CoroutineScope.buzz() = produce使? receive 掛起函數(shù),我們可以從兩個(gè)通道接收 其中?個(gè) 的數(shù)據(jù)。但是 select 表達(dá)式允許我們使? 其 onReceive ?句 同時(shí) 從兩者接收:
suspend fun selectFizzBuzz(fizz: ReceiveChannel讓我們運(yùn)?代碼 7 次:
val fizz = fizz() val buzz = buzz() repeat(7) { selectFizzBuzz(fizz, buzz) } coroutineContext.cancelChildren() // 取消 fizz 和 buzz 協(xié)程這段代碼的執(zhí)?結(jié)果如下:
fizz -> 'Fizz' buzz -> 'Buzz!' fizz -> 'Fizz' fizz -> 'Fizz' buzz -> 'Buzz!' fizz -> 'Fizz' buzz -> 'Buzz!'通道關(guān)閉時(shí) select
select 中的 onReceive ?句在已經(jīng)關(guān)閉的通道執(zhí)?會(huì)發(fā)?失敗,并導(dǎo)致相應(yīng)的 select 拋出異常。我 們可以使? onReceiveOrNull ?句在關(guān)閉通道時(shí)執(zhí)?特定操作。以下?例還顯?了 select 是?個(gè)返 回其查詢?法結(jié)果的表達(dá)式:
suspend fun selectAorB(a: ReceiveChannel注意,onReceiveOrNull 是?個(gè)僅在?于不可空元素的通道上定義的擴(kuò)展函數(shù),以使關(guān)閉的通道與空值 之間不會(huì)出現(xiàn)意外的混亂。 現(xiàn)在有?個(gè)?成四次“Hello”字符串的 a 通道,和?個(gè)?成四次“World”字符串的 b 通道,我們在這 兩個(gè)通道上使?它:
val a = produce這段代碼的結(jié)果?常有趣,所以我們將在細(xì)節(jié)中分析它:
a -> 'Hello 0' a -> 'Hello 1' b -> 'World 0' a -> 'Hello 2' a -> 'Hello 3' b -> 'World 1' Channel 'a' is closed Channel 'a' is closed有?個(gè)結(jié)果可以通過觀察得出。
?先,select 偏向于 第?個(gè)?句,當(dāng)可以同時(shí)選到多個(gè)?句時(shí),第?個(gè)?句將被選中。在這?,兩個(gè)通 道都在不斷地?成字符串,因此 a 通道作為 select 中的第?個(gè)?句獲勝。然?因?yàn)槲覀兪?的是?緩 沖通道,所以 a 在其調(diào)? send 時(shí)會(huì)不時(shí)地被掛起,進(jìn)? b 也有機(jī)會(huì)發(fā)送。
第?個(gè)觀察結(jié)果是,當(dāng)通道已經(jīng)關(guān)閉時(shí),會(huì)?即選擇 onReceiveOrNull。
Select 以發(fā)送
Select 表達(dá)式具有 onSend ?句,可以很好的與選擇的偏向特性結(jié)合使?。
我們來編寫?個(gè)整數(shù)?成器的?例,當(dāng)主通道上的消費(fèi)者?法跟上它時(shí),它會(huì)將值發(fā)送到 side 通道 上:
fun CoroutineScope.produceNumbers(side: SendChannel消費(fèi)者將會(huì)?常緩慢,每個(gè)數(shù)值處理需要 250 毫秒:
val side = Channel讓我們看看會(huì)發(fā)?什么:
Consuming 1 Side channel has 2 Side channel has 3 Consuming 4 Side channel has 5 Side channel has 6 Consuming 7 Side channel has 8 Side channel has 9 Consuming 10 Done consumingSelect 延遲值
延遲值可以使? onAwait ?句查詢。讓我們啟動(dòng)?個(gè)異步函數(shù),它在隨機(jī)的延遲后會(huì)延遲返回字符串:
fun CoroutineScope.asyncString(time: Int) = async { delay(time.toLong()) "Waited for $time ms" }讓我們隨機(jī)啟動(dòng)?余個(gè)異步函數(shù),每個(gè)都延遲隨機(jī)的時(shí)間。
fun CoroutineScope.asyncStringsList(): List現(xiàn)在 main 函數(shù)在等待第?個(gè)函數(shù)完成,并統(tǒng)計(jì)仍處于激活狀態(tài)的延遲值的數(shù)量。注意,我們在這?使? select 表達(dá)式事實(shí)上是作為?種 Kotlin DSL,所以我們可以?任意代碼為它提供?句。在這種情況 下,我們遍歷?個(gè)延遲值的隊(duì)列,并為每個(gè)延遲值提供 onAwait ?句的調(diào)?。
val list = asyncStringsList() val result = select該輸出如下:
Deferred 4 produced answer 'Waited for 128 ms' 11 coroutines are still active在延遲值通道上切換
我們現(xiàn)在來編寫?個(gè)通道?產(chǎn)者函數(shù),它消費(fèi)?個(gè)產(chǎn)?延遲字符串的通道,并等待每個(gè)接收的延遲值, 但它只在下?個(gè)延遲值到達(dá)或者通道關(guān)閉之前處于運(yùn)?狀態(tài)。此?例將 onReceiveOrNull 和 onAwait ?句放在同?個(gè) select 中:
fun CoroutineScope.switchMapDeferreds(input: ReceiveChannel為了測試它,我們將??個(gè)簡單的異步函數(shù),它在特定的延遲后返回特定的字符串:
fun CoroutineScope.asyncString(str: String, time: Long) = async { delay(time) str }main 函數(shù)只是啟動(dòng)?個(gè)協(xié)程來打印 switchMapDeferreds 的結(jié)果并向它發(fā)送?些測試數(shù)據(jù):
val chan = Channel這段代碼的執(zhí)?結(jié)果:
BEGIN Replace END Channel was closed