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 & JS Effect – Button Hover Bling Bling Effect

    效果 原理 一眼看上去, background 有渐变颜色 linear-gradient. 当 hover in 的时候有一束白光, 从右边移动到左边. hover out 则是反过来. 它其实是通 ...

  2. ASP.NET Core Library – MailKit SMTP Client

    前言 以前写的 SMTP Client 相关文章: Asp.net core 学习笔记 ( Smtp and Razor template 电子邮件和 Razor 模板 ) ASP.NET Email ...

  3. Web刷题之polarctf靶场(2)

    1.蜜雪冰城吉警店 点开靶场, 发现题目说点到隐藏奶茶(也就是第九杯)就给flag, 但是明显就只有八杯, 猜测大概率考的是前端代码修改 把id=1修改为id=9, 然后回到页面点击原味奶茶即可弹出f ...

  4. [32](CSP 集训) CSP-S 模拟 3

    A 奇观 考虑到 CCF 可以拆开算,答案为 \((ans_c)^2\times ans_f\) 剩下的东西比较少,考虑 DP 我的 dp 是从爆搜改的,设 \(f_{i,j}\) 表示递归到第 \( ...

  5. 暑假集训CSP提高模拟5

    听好了: 7 月 22 日,比样的学长就此陷落.每个陷落的学长都将迎来一场模拟赛,为这些模拟赛带来全新的题面. 你所熟知的一切都将改变,你所熟悉的算法都将加诸比样的考验. 至此,一锤定音. 尘埃,已然 ...

  6. ServiceMesh 3:路由控制(图文总结)

    ★ ServiceMesh系列 1 Istio部署 1.1 连接测试机 进入测试机服务器... 1.2 安装Istio 1.2.1 通过官方网站下载Istio # 下载最新版本的Istio $ cur ...

  7. 比赛题解 更新ING

    CF Codeforces Round #750 (Div. 2) (水题.组合数学.双指针+搜索.构造.dp.dp) Codeforces Round #747 (Div. 2) (水题.水题.埃筛 ...

  8. 什么是前后端分离应用(Full-stack Separation),想当然就会理解错

    前后端分离应用指的是将应用的前端部分(用户界面与交互逻辑)和后端部分(业务逻辑.数据处理.服务器响应)拆分成独立的模块,各自通过 API 进行通信.这种架构设计的目的是提高开发效率.增强可扩展性和灵活 ...

  9. hydra爆破工具

    hydra爆破工具 命令详细: 1.破解ssh: hydra -l 用户名 -p 密码字典 -t 线程 -vV -e ns ip ssh hydra -l 用户名 -p 密码字典 -t 线程 -o s ...

  10. SpringBoot项目集成MinIO

    一.MinIO的下载安装以及基本使用 1.下载地址:https://dl.min.io/server/minio/release/windows-amd64/minio.exe 2.下载好后需要手动创 ...