Kotlin コルーチン - 多重 select()

1. コンセプト

        これは選択式とも呼ばれ、複数の保留中の結果を同時に待機し、最も速く回復した値のみを使用できる一時停止関数です (つまり、複数の方法でデータを取得し、結果をより速く返す方法)。

        select() が同時に到達した場合、部分式が先に書かれますが、ランダム (公平) にしたい場合は、 selectUnbiased() を使用して を置き換えます。

        選択できるのはSelectClauseN関数の種類です。

public stop inline fun <R> select(crossinline builder: SelectBuilder<R>.() -> Unit): R 

パブリック シールド インターフェイス SelectBuilder<in R> {

        パブリック オペレーター fun SelectClause0.invoke(block: サスペンド () -> R)
        パブリック オペレーター fun <Q> SelectClause1<Q>.invoke(block: サスペンド (Q) -> R)
        パブリック オペレーター fun <P, Q> SelectClause2<P , Q>.invoke(param: P, block: サスペンド (Q) -> R)
        パブリック オペレーター fun <P, Q> SelectClause2<P?, Q>.invoke(block: サスペンド (Q) -> R): 単位= 呼び出し(null, ブロック)
}

SelectClause0 対応するイベントには戻り値がありません。たとえば、job.onJoin。
選択条項 1 対応するイベントには戻り値があります。たとえば、defered.onAwait や channel.onReceive などです。
選択条項 2 対応するイベントには戻り値があります。さらに、追加のパラメータが必要です。たとえば、Channel.onSend() には 2 つのパラメータがあります。1 つ目は、送信する値を示す Channel データ型の値で、2 つ目は、送信が成功したときのコールバック関数です。 。

2. 使用する

async() を使用してコルーチンを開始する戻り値の型 Deferred では、SelectClause1 関数型の変数 onAwait が定義されています。その関数は、select( のサブステートメントとして使用される場合を除いて、await() と同じです。 )には、「同時に誰が待っているかを確認して待つ」「先に戻る」効果があります。他のことについても同様です。

2.1 複数の job.onJoin を再利用する

fun main() = runBlocking<Unit> {
    val job1 = launch {
        delay(100)
        println("job 1")
    }
    val job2 = launch {
        delay(10)
        println("job 2")
    }
    select {
        job1.onJoin { println("job 1 更快") }
        job2.onJoin { println("job 2 更快") }
    }
    delay(1000)
}
//打印:
//job 2
//job 2 更快
//job 1

2.2 複数の deffered.onAwait を再利用する

public Interface Deferred<out T> : Job {         public val onAwait: SelectClause1<T> //等效await()

fun main() = runBlocking {
    val defferedCache = async {
        delay(10)
        "Cache"
    }
    val defferedLocal = async {
        delay(100)
        "Local"
    }
    val defferedRemote = async {
        delay(1000)
        "Remote"
    }
    val result = select {
        defferedCache.onAwait { println("最快的是$it") }
        defferedLocal.onAwait { println("最快的是$it") }
        defferedRemote.onAwait { println("最快的是$it") }
    }
    delay(2000)
    println(result) //打印:最快的是Cache
}

2.3 複数チャネルの多重化.onReceive

パブリック インターフェイス SendChannel<in E> {

        public val onSend: SelectClause2<E, SendChannel<E>> //send() と同等

}

パブリック インターフェイス ReceiveChannel<out E> {

        public val onReceive: SelectClause1<E> //等效receive()

        public stop fun acceptCatching(): ChannelResult<E> //等效receiveCatching()

}

//select() の OnReceive() は、閉じられたチャネルでの実行に失敗し、対応する select() が例外をスローします。チャネルを閉じるときに特定の操作を実行するには、onReceiveCatching() を使用します。

suspend fun getDataFromLocal() = withContext(Dispatchers.IO) { "Local" }
suspend fun getDataFromRemote() = withContext(Dispatchers.IO) { "Remote" }

@OptIn(ExperimentalCoroutinesApi::class)
fun main() = runBlocking {
    val produceLocal = produce { send(getDataFromLocal()) }
    val produceRemote = produce { send(getDataFromRemote()) }
    val result = select {
        produceLocal.onReceive { it }
        produceRemote.onReceive { it }
    }
//    val result = select {
//        produceLocal.onReceiveCatching { it.getOrNull() ?: "Channel已关闭:produceLocal" }
//        produceRemote.onReceiveCatching { it.getOrNull() ?: "Channel已关闭:produceRemote " }
//    }
    println("结果更快的是:$result")
}

おすすめ

転載: blog.csdn.net/HugMua/article/details/132613352