【Kotlin】select简介
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 select 在 Channel 中的应用
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 源码
onSend 是 Channel 中定义的属性。
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 源码
onReceive 是 Channel 中定义的属性。
public val onReceive: SelectClause1<E>
说明:在调用 channels[0].onReceive { xxx } 时,等价于调用了 SelectClause1.invoke 函数,也等价于调用了 SelectClause1.registerSelectClause1 函数。
声明:本文转自【Kotlin】select简介。
【Kotlin】select简介的更多相关文章
- Kotlin入门简介
Kotlin的“简历” 来自于著名的IDE IntelliJ IDEA(Android Studio基于此开发) 软件开发公司 JetBrains(位于东欧捷克) 起源来自JetBrains的圣彼得堡 ...
- Kotlin【简介】Android开发 配置 扩展
重要资源 官方资源:官网 . 官网源码 .官网文档 . 在线 IDE .GitHub 中文资源:中文官网 .中文文档 离线文档:PDF 文件 . PDF 文件 GitBook 版 .ePUB 文件 ...
- 谁说接口不能有代码?—— Kotlin接口简介(KAD 26)
作者:Antonio Leiva 时间:Jun 6, 2017 原文链接:https://antonioleiva.com/interfaces-kotlin/ 与Java相比,Kotlin接口允许你 ...
- I/O复用select 使用简介
一:五种I/O模型区分: 1.阻塞I/O模型 最流行的I/O模型是阻塞I/O模型,缺省情形下,所有套接口都是阻塞的.我们以数据报套接口为例来讲解此模型(我们使用UDP而不是TCP作为例子的原 ...
- 初识Kotlin之函数
本章通过介绍Kotlin的基本函数,默认参数函数,参数不定长函数,尾递归函数,高阶函数,Lamdba表达式.来对Kotlin函数做进一步了解.将上一篇的Kotlin变量的知识得以运用.Kotlin变量 ...
- seql sever INSERT语句简介
INSERT语句简介 要向表中添加一行或多行,可以使用INSERT语句.下面说明了INSERT语句的最基本形式: INSERT INTO table_name (column_list) VA ...
- 最全的ORACLE-SQL笔记
-- 首先,以超级管理员的身份登录oracle sqlplus sys/bjsxt as sysdba --然后,解除对scott用户的锁 alter user scott account unloc ...
- USB Mass Storage协议分析
目录 简介 指令数据和状态协议 CBW指令格式 CSWCommand Status Wrapper状态格式 SCSI命令集 Format Unit Inquiry MODE SELECT 简介 USB ...
- html简单的知识
分布式版本控制git pwd查询当前目录 ls ls -la git config --global user.name xxx git config --global user. ...
- html - 表单form
一.表单 功能:表单用于向服务器传输数据,从而实现用户与Web服务器的交互 表单能够包含input系列标签,比如文本字段.复选框.单选框.提交按钮等等. 表单还可以包含textarea.select. ...
随机推荐
- CSS & JS Effect – Button Hover Bling Bling Effect
效果 原理 一眼看上去, background 有渐变颜色 linear-gradient. 当 hover in 的时候有一束白光, 从右边移动到左边. hover out 则是反过来. 它其实是通 ...
- ASP.NET Core Library – MailKit SMTP Client
前言 以前写的 SMTP Client 相关文章: Asp.net core 学习笔记 ( Smtp and Razor template 电子邮件和 Razor 模板 ) ASP.NET Email ...
- Web刷题之polarctf靶场(2)
1.蜜雪冰城吉警店 点开靶场, 发现题目说点到隐藏奶茶(也就是第九杯)就给flag, 但是明显就只有八杯, 猜测大概率考的是前端代码修改 把id=1修改为id=9, 然后回到页面点击原味奶茶即可弹出f ...
- [32](CSP 集训) CSP-S 模拟 3
A 奇观 考虑到 CCF 可以拆开算,答案为 \((ans_c)^2\times ans_f\) 剩下的东西比较少,考虑 DP 我的 dp 是从爆搜改的,设 \(f_{i,j}\) 表示递归到第 \( ...
- 暑假集训CSP提高模拟5
听好了: 7 月 22 日,比样的学长就此陷落.每个陷落的学长都将迎来一场模拟赛,为这些模拟赛带来全新的题面. 你所熟知的一切都将改变,你所熟悉的算法都将加诸比样的考验. 至此,一锤定音. 尘埃,已然 ...
- ServiceMesh 3:路由控制(图文总结)
★ ServiceMesh系列 1 Istio部署 1.1 连接测试机 进入测试机服务器... 1.2 安装Istio 1.2.1 通过官方网站下载Istio # 下载最新版本的Istio $ cur ...
- 比赛题解 更新ING
CF Codeforces Round #750 (Div. 2) (水题.组合数学.双指针+搜索.构造.dp.dp) Codeforces Round #747 (Div. 2) (水题.水题.埃筛 ...
- 什么是前后端分离应用(Full-stack Separation),想当然就会理解错
前后端分离应用指的是将应用的前端部分(用户界面与交互逻辑)和后端部分(业务逻辑.数据处理.服务器响应)拆分成独立的模块,各自通过 API 进行通信.这种架构设计的目的是提高开发效率.增强可扩展性和灵活 ...
- hydra爆破工具
hydra爆破工具 命令详细: 1.破解ssh: hydra -l 用户名 -p 密码字典 -t 线程 -vV -e ns ip ssh hydra -l 用户名 -p 密码字典 -t 线程 -o s ...
- SpringBoot项目集成MinIO
一.MinIO的下载安装以及基本使用 1.下载地址:https://dl.min.io/server/minio/release/windows-amd64/minio.exe 2.下载好后需要手动创 ...