【Kotlin】select简介

devtools/2024/9/23 2:56:40/

1 前言

        协程的 select 是一种用于异步操作的选择器,它允许同时等待多个挂起函数的结果,并在其中一个完成时执行相应的操作。

        能够被 select 的事件都是 SelectClause,在 select.kt 中有定义,如下。

public interface SelectBuilder<in R> {public operator fun SelectClause0.invoke(block: suspend () -> R)public operator fun <Q> SelectClause1<Q>.invoke(block: suspend (Q) -> R)public operator fun <P, Q> SelectClause2<P, Q>.invoke(param: P, block: suspend (Q) -> R)public operator fun <P, Q> SelectClause2<P?, Q>.invoke(block: suspend (Q) -> R): Unit = invoke(null, block)...
}public interface SelectClause0 {public fun <R> registerSelectClause0(select: SelectInstance<R>, block: suspend () -> R)
}public interface SelectClause1<out Q> {public fun <R> registerSelectClause1(select: SelectInstance<R>, block: suspend (Q) -> R)
}public interface SelectClause2<in P, out Q> {public fun <R> registerSelectClause2(select: SelectInstance<R>, param: P, block: suspend (Q) -> R)
}internal class SelectBuilderImpl<in R>(private val uCont: Continuation<R>
) : LockFreeLinkedListHead(), SelectBuilder<R>,SelectInstance<R>, Continuation<R>, CoroutineStackFrame
{override fun SelectClause0.invoke(block: suspend () -> R) {registerSelectClause0(this@SelectBuilderImpl, block)}override fun <Q> SelectClause1<Q>.invoke(block: suspend (Q) -> R) {registerSelectClause1(this@SelectBuilderImpl, block)}override fun <P, Q> SelectClause2<P, Q>.invoke(param: P, block: suspend (Q) -> R) {registerSelectClause2(this@SelectBuilderImpl, param, block)}
}

2 select 在 Job 中的应用

         1)应用

fun main() {CoroutineScope(Dispatchers.Default).launch {var job1 = launchJob("job-1", 100)var job2 = launchJob("job-2", 200)var res = select {job1.onJoin { "select: 1" }job2.onJoin { "select: 2" }}println(res) // 打印: select: 1}Thread.sleep(1000) // 阻塞当前线程, 避免程序过早结束, 协程提前取消
}suspend fun launchJob(tag: String, delayTime: Long): Job =CoroutineScope(Dispatchers.Default).launch {println("tag")delay(delayTime)}

        打印如下。

tag
tag
select: 1

        2)onJoin 源码

        onJoin 是 Job 中定义的属性。

public val onJoin: SelectClause0

        说明:在调用 job1.onJoin { xxx } 时,等价于调用了 SelectClause0.invoke 函数,也等价于调用了 SelectClause0.registerSelectClause0 函数。

3 select 在 Deferred 中的应用

        1)应用

fun main() {CoroutineScope(Dispatchers.Default).launch {var task1 = asyncTask("task-1", 100)var task2 = asyncTask("task-2", 200)var res = select {task1.onAwait { "select: $it" }task2.onAwait { "select: $it" }}println(res) // 打印: select: task-1}Thread.sleep(1000) // 阻塞当前线程, 避免程序过早结束, 协程提前取消
}suspend fun asyncTask(tag: String, delayTime: Long): Deferred<String> =CoroutineScope(Dispatchers.Default).async {delay(delayTime)tag}

        打印如下。

select: task-1

        2)onAwait 源码

        onAwait 是 Deferred 中定义的属性。

public val onAwait: SelectClause1<T>

        说明:在调用 task1.onAwait { xxx } 时,等价于调用了 SelectClause1.invoke 函数,也等价于调用了 SelectClause1.registerSelectClause1 函数。

4 selectChannel 中的应用

4.1 onSend

        1)应用

fun main() {var channels = List(2) { Channel<String>() }CoroutineScope(Dispatchers.Default).launch {var res = select {channels[0].onSend("select-1") { "task-1" }channels[1].onSend("select-2") { "task-2" }}println("res=$res") // 打印: res=task-2}receiveTask(200, channels[0])receiveTask(100, channels[1])Thread.sleep(1000) // 阻塞当前线程, 避免程序过早结束, 协程提前取消
}fun receiveTask(delayTime: Long, channel: Channel<String>) {CoroutineScope(Dispatchers.Default).launch {delay(delayTime)var element = channel.receive()println("receive: $element")}
}

        打印如下。

receive: select-2
res=task-2

        2)onSend 源码

        onSendChannel 中定义的属性。

public val onSend: SelectClause1<E>

        说明:在调用 channels[0].onSend(xxx) { yyy } 时,等价于调用了 SelectClause2.invoke 函数,也等价于调用了 SelectClause2.registerSelectClause2 函数。

4.2 onReceive

        1)应用

fun main() {var channels = List(2) { Channel<String>() }sendTask("task-1", 200, channels[0])sendTask("task-2", 100, channels[1])CoroutineScope(Dispatchers.Default).launch {var res = select {channels[0].onReceive { "select: $it" }channels[1].onReceive { "select: $it" }}println(res) // 打印: select: task-2}Thread.sleep(1000) // 阻塞当前线程, 避免程序过早结束, 协程提前取消
}fun sendTask(tag: String, delayTime: Long, channel: Channel<String>) {CoroutineScope(Dispatchers.Default).launch {delay(delayTime)channel.send(tag)}
}

        打印如下。

select: task-2

        2)onReceive 源码

        onReceiveChannel 中定义的属性。

public val onReceive: SelectClause1<E>

        说明:在调用 channels[0].onReceive { xxx } 时,等价于调用了 SelectClause1.invoke 函数,也等价于调用了 SelectClause1.registerSelectClause1 函数。


http://www.ppmy.cn/devtools/23124.html

相关文章

Android 音视频基础知识

本系列文章会介绍两个 Android NDK Demo&#xff0c;拉流端会实现一个基于 FFmpeg 的视频播放器 Demo&#xff0c;推流端会实现一个视频直播 Demo&#xff0c;当然在做 Demo 之前会介绍音视频的基础知识。以下是本系列文章的目录&#xff1a; Android 音视频基础知识 Android 音…

源代码加密

需求背景 随着各行各业业务数据信息化发展&#xff0c;各类产品研发及设计等行业&#xff0c;都有关乎自身发展的核心数据&#xff0c;包括业务数据、代码数据、机密文档、用户数据等敏感信息&#xff0c;这些信息数据有以下共性&#xff1a; 属于核心机密资料&#xff0c;万一…

pytest测试基础

assert 验证关键字 需要pahton版本大于3.6&#xff0c;因为有个工具pip3;因为做了映射&#xff0c;所以下面命令pip3即pip pip install -U pytest -U参数可选&#xff0c;是如果已安装可更新。 如果上述demo变化 通过验证代码&#xff0c;测试环境没问题。…

AI智能绘画系统源码 智能生成思维导图 带完整的安装代码包以及搭建教程

在数字化时代&#xff0c;人们对于艺术创作的需求越来越多样化&#xff0c;而传统的绘画方式往往受限于时间和技巧。因此&#xff0c;开发一款能够智能生成绘画作品的系统显得尤为重要。同时&#xff0c;思维导图作为一种有效的知识管理工具&#xff0c;也受到了广泛的关注。将…

【排序算法】快速排序

快速排序&#xff08;Quick Sort&#xff09;是一种常用的排序算法&#xff0c;它采用分而治之的策略来对一个序列进行排序。快速排序的基本思想是选择一个基准元素&#xff08;通常是序列中的第一个元素&#xff09;&#xff0c;然后将序列中的其他元素分为两个子序列&#xf…

Java基础--单元测试

JUnit是Java中最流行的开源单元测试框架&#xff0c;用于编写和运行可重复的、自动化的单元测试。JUnit极大地简化了测试用例的编写和组织&#xff0c;提供了丰富的断言方法、测试运行控制、测试结果报告等功能&#xff0c;是遵循测试驱动开发&#xff08;TDD&#xff09;和持续…

Qt学习笔记1.3.1 Qt Core-容器类

文章目录 简介容器类迭代器类JAVA风格迭代器STL风格迭代器隐式共享问题 foreach关键字其他容器类算法复杂度增长策略 来源: https://doc.qt.io/archives/qt-5.12/containers.html 简介 Qt库提供基于模板的通用容器类&#xff0c;相比STL容器类更轻量化、安全和易用。 容器类…

C语言——自定义数据类型(结构体内存对齐)

C语言中不只有内置类型诸如 int 、float、char 等类型&#xff0c;还有自定义数据类型&#xff0c;本文主要探讨结构体&#xff08;struct&#xff09;、联合体&#xff08;union&#xff09;、枚举&#xff08;enum&#xff09;三种自定义数据类型。 在我之前的文章《C语言—…