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简介的更多相关文章

  1. Kotlin入门简介

    Kotlin的“简历” 来自于著名的IDE IntelliJ IDEA(Android Studio基于此开发) 软件开发公司 JetBrains(位于东欧捷克) 起源来自JetBrains的圣彼得堡 ...

  2. Kotlin【简介】Android开发 配置 扩展

    重要资源 官方资源:官网 . 官网源码 .官网文档 . 在线 IDE .GitHub 中文资源:中文官网 .中文文档  离线文档:PDF 文件 . PDF 文件 GitBook 版 .ePUB 文件  ...

  3. 谁说接口不能有代码?—— Kotlin接口简介(KAD 26)

    作者:Antonio Leiva 时间:Jun 6, 2017 原文链接:https://antonioleiva.com/interfaces-kotlin/ 与Java相比,Kotlin接口允许你 ...

  4. I/O复用select 使用简介

    一:五种I/O模型区分: 1.阻塞I/O模型      最流行的I/O模型是阻塞I/O模型,缺省情形下,所有套接口都是阻塞的.我们以数据报套接口为例来讲解此模型(我们使用UDP而不是TCP作为例子的原 ...

  5. 初识Kotlin之函数

    本章通过介绍Kotlin的基本函数,默认参数函数,参数不定长函数,尾递归函数,高阶函数,Lamdba表达式.来对Kotlin函数做进一步了解.将上一篇的Kotlin变量的知识得以运用.Kotlin变量 ...

  6. seql sever INSERT语句简介

    INSERT语句简介 要向表中添加一行或多行,可以使用INSERT语句.下面说明了INSERT语句的最基本形式:   INSERT INTO table_name (column_list)   VA ...

  7. 最全的ORACLE-SQL笔记

    -- 首先,以超级管理员的身份登录oracle sqlplus sys/bjsxt as sysdba --然后,解除对scott用户的锁 alter user scott account unloc ...

  8. USB Mass Storage协议分析

    目录 简介 指令数据和状态协议 CBW指令格式 CSWCommand Status Wrapper状态格式 SCSI命令集 Format Unit Inquiry MODE SELECT 简介 USB ...

  9. html简单的知识

    分布式版本控制git       pwd查询当前目录 ls ls -la   git config --global user.name xxx   git config --global user. ...

  10. html - 表单form

    一.表单 功能:表单用于向服务器传输数据,从而实现用户与Web服务器的交互 表单能够包含input系列标签,比如文本字段.复选框.单选框.提交按钮等等. 表单还可以包含textarea.select. ...

随机推荐

  1. HTML – Emmet Shortcut

    前言 程序员就爱 hot key, 就爱 shortcut. 当然这里指的是不牺牲安全和结果的情况下用尽可能少的力气去做事情, 而不是那种 shortcut 了以后会翻车的. Emmet 就是专门写 ...

  2. Asp.net core 学习笔记之 authen + autho + oidc + oauth + spa 第九篇 (external login)

    External login 就是指通过 Google, Microsoft, Facebook account 做登入. https://docs.microsoft.com/en-us/aspne ...

  3. 从0到1搭建权限管理系统系列三 .net8 JWT创建Token并使用

    说明 该文章是属于OverallAuth2.0系列文章,每周更新一篇该系列文章(从0到1完成系统开发). 该系统文章,我会尽量说的非常详细,做到不管新手.老手都能看懂. 说明:OverallAuth2 ...

  4. C#上位机与PLC通信心跳的实现方法

    -Begin- 大家好!我是付工.众所周知,在工业自动化控制系统中,上位机与下位机之间的通信是实现自动化生产的关键环节之一.为了确保通信的稳定性和可靠性,我们通用会采用一种被称为[心跳机制]的方法,它 ...

  5. AE cc 2017 和 2018 中英文切换的方法

    AE cc 2017中文切换英文的方法 找到AE的安装文件目录下的"Support Files"文件夹,路径为 C:\Program Files\Adobe\Adobe After ...

  6. 【赵渝强老师】什么是PL/SQL?

    一.什么是PL/SQL? PL/SQL(Procedure Language/SQL)是oracle在标准的sql语言上的扩展.ql/sql不仅允许嵌入sql语言,还可以定义变量和常量,允许私用条件语 ...

  7. 高强度学习训练第七天总结:JVM分配内存机制

    理解JVM内存分配策略 三大原则+担保机制 JVM分配内存机制有三大原则和担保机制 具体如下所示: 优先分配到eden区 大对象,直接进入到老年代 长期存活的对象分配到老年代 空间分配担保 对象优先在 ...

  8. 「模拟赛」A 层多校联训 4(卖品:CTH)

    双倒一啦! 感觉这次最大的错误就是没看 T2.(本质原因还是时间浪费的太多了) 赛时记录在闲话啦 accoder 多校比赛链接 02 表示法 唐诗题!考高精的人都\(**\),输出深度优先搜索解决.高 ...

  9. Spring事务的1道面试题

    每次聊起Spring事务,好像很熟悉,又好像很陌生.本篇通过一道面试题和一些实践,来拆解几个Spring事务的常见坑点. 原理 Spring事务的原理是:通过AOP切面的方式实现的,也就是通过代理模式 ...

  10. fatal: couldn't find remote ref XXX解决

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...