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. CSS – Sass & SCSS

    前言 CSS 代码多了就不好管理了, 这是它语法先天的不足. Sass 就是加强它语法的, Sass 为 CSS 引入了一些 JS 语言的特性, 比如 variable, function, para ...

  2. EF Core – Unit of Work, DbContext, Transaction 概念解释

    前言 踩了一个坑, 下面是 2 个 scope 的调用, 第 1 和 3 是一个 Audit log filter action, 第 2 个是 controller. // open tran // ...

  3. ASP.NET Core C# 反射 & 表达式树 (第四篇)

    前言 上一篇说完了动态创建表达式树, 这篇来说一说解析表达式树. 我之所以会用到是因为最近开始大量使用 trigger 来维护冗余. 但 trigger 本身并不好维护 (EF Core 也不支持), ...

  4. uni-app v3.0.0-alpha-3090220231010001

    https://uniapp.dcloud.net.cn/tutorial/ #-------------------------------------------------------- 未分类 ...

  5. Parquet.Net: 将 Apache Parquet 移植到 .NET

    Parquet.Net 是一个用于读取和写入 Apache Parquet 文件的纯 .NET 库,使用MIT协议开源,github仓库:https://github.com/aloneguid/pa ...

  6. union联合体的缺陷

    传统的 union 联合体在 C++ 中虽然提供了一种能够在相同的内存空间内存储多种不同类型的方式,但它也有一些显著的缺陷和限制.这些缺陷让 union 的使用不太安全,尤其是在复杂的程序中.以下是传 ...

  7. USB gadget驱动框架(五)

    本节主要分析虚拟串口的tty设备的注册.创建/dev/ttyGSx设备节点.tty相关接口的实现. tty的申请与注册 源码:drivers/usb/gadget/function/u_serial. ...

  8. 【PyTorch】state_dict详解

    这篇博客来自csdn,完全用于学习. Introduce 在pytorch中,torch.nn.Module模块中的state_dict变量存放训练过程中需要学习的权重和偏执系数,state_dict ...

  9. 精彩回顾|【2023 ACDU 中国行·深圳站】数据库主题交流活动成功举办!

    6月30日下午,[ACDU 中国行·深圳站]在深圳回酒店圆满落下帷幕.本次活动由中国数据库联盟(ACDU)联合墨天轮社区主办,围绕「数据库前沿技术揭秘及应用」这一主题,七位数据库行业的领军人物从数据库 ...

  10. 77.const声明对象修改对象里面的值会触发报错吗

    不会,因为对象是复杂类型数据 :对象的地址保存在栈内存中,对象的数据保存在堆内存中 : 只要对象的地址不发生改变,无论堆内存的对象数据如何改变,对象的值就不会改变 :