【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 函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/582285.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何修改php版本

我使用的Hostease的Windows虚拟主机产品,由于网站程序需要支持高版本的PHP,程序已经上传到主机&#xff0c;但是没有找到切换PHP以及查看PHP有哪些版本的位置&#xff0c;因此咨询了Hostease的技术支持&#xff0c;寻求帮助了解到可以实现在Plesk面板上找到此切换PHP版本的按钮…

linux tcpdump的交叉编译以及使用

一、源码下载 官网&#xff1a;点击跳转 二、编译 1、解压 tar -xf libpcap-1.10.4.tar.xz tar -xf tcpdump-4.99.4.tar.xz 2、配置及编译 //libpcap&#xff1a; ./configure --hostarm-linux --targetarm-linux CCarm-linux-gcc --with-pcaplinux --prefix$PWD/build//t…

37 线程控制

内核中没有明确的线程的概念&#xff0c;线程作为轻量级进程。所以不会提供线程的系统调用&#xff0c;只提供了轻量级进程的系统调用&#xff0c;但这个接口比较复杂&#xff0c;使用很不方便&#xff0c;我们用户&#xff0c;需要一个线程的接口。应用层对轻量级进程的接口进…

企业如何保证内部传输文件使用的工具是安全的?

企业内部文件的频繁交换成为了日常运营不可或缺的一环。然而&#xff0c;随着数据量的爆炸式增长和网络攻击手段的日益复杂&#xff0c;内网文件传输的安全隐患也日益凸显&#xff0c;成为企业信息安全的薄弱环节。本文将探讨内网文件传输的安全风险、企业常用的防护措施。 内网…

Python轻量级Web框架Flask(12)—— Flask类视图实现前后端分离

0、前言&#xff1a; 在学习类视图之前要了解前后端分离的概念&#xff0c;相对于之前的模板&#xff0c;前后端分离的模板会去除views文件&#xff0c;添加两个新python文件apis和urls&#xff0c;其中apis是用于传输数据和解析数据 的&#xff0c;urls是用于写模板路径的。 …

终于有人把无人机5G通信原理讲清楚了

在现代科技快速发展的背景下&#xff0c;无人机技术在各个领域都有了广泛应用&#xff0c;从送外卖到农业监控&#xff0c;无人机正变得越来越普遍。然而&#xff0c;无人机的效能很大程度上受到其通信系统的限制&#xff0c;尤其是在城市这种高楼林立、障碍物众多的环境中。为…

五一旅游必备物品清单 建议把这份清单记在备忘录

五一小长假就要来临&#xff0c;相信很多人已经跃跃欲试&#xff0c;准备带着家人或朋友外出旅游&#xff0c;享受这难得的休闲时光。出游总是让人兴奋不已&#xff0c;但带小孩出游&#xff0c;行李准备可是一项大工程。为了让旅程更加顺利&#xff0c;提前列一份必备物品清单…

Python绘制3D曲面图

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 探索Python中绘制3D曲面图的艺术 在数据可视化的世界中&#xff0c;3D曲面图是一种强大的工…

压铸机PQ控制阀比例放大器

压铸机PQ控制阀比例放大器是确保压铸机正常工作的重要组成部分&#xff0c;它通常由多种液压元件组成&#xff0c;负责提供动力和控制系统中各个部件的运动。液压系统通过液体&#xff08;通常是油&#xff09;传递压力能&#xff0c;以驱动机械装置工作。在压铸机中&#xff0…

ElasticSearch教程入门到精通——第五部分(基于ELK技术栈elasticsearch 7.x+8.x新特性)

ElasticSearch教程入门到精通——第五部分&#xff08;基于ELK技术栈elasticsearch 7.x8.x新特性&#xff09; 1. Elasticsearch集成1.1 框架集成-SpringData-整体介绍1.2 Spring Data Elasticsearch 介绍1.3 框架集成-SpringData-代码功能集成1.3.1 创建Maven项目1.3.2 修改po…

[C++] 类和对象 _ 剖析构造、析构与拷贝

一、构造函数 构造函数是特殊的成员函数&#xff0c;它在创建对象时自动调用。其主要作用是初始化对象的成员变量&#xff08;不是开辟空间&#xff09;。构造函数的名字必须与类名相同&#xff0c;且没有返回类型&#xff08;即使是void也不行&#xff09;。 在C中&#xff0…

Yolov5简单部署(使用自己的数据集)

一.注意事项 1.本文主要是引用大佬的文章&#xff08;侵权请联系&#xff0c;马上删除&#xff09;&#xff0c;做的工作为简单补充 二.正文 1.大体流程按照 准备&#xff1a;【简单易懂&#xff0c;一看就会】yolov5保姆级环境搭建_哔哩哔哩_bilibili 主要过程&#xff1…

Java | Leetcode Java题解之第55题跳跃游戏

题目&#xff1a; 题解&#xff1a; public class Solution {public boolean canJump(int[] nums) {int n nums.length;int rightmost 0;for (int i 0; i < n; i) {if (i < rightmost) {rightmost Math.max(rightmost, i nums[i]);if (rightmost > n - 1) {retu…

VitePress 构建的博客如何部署到 github 平台?

VitePress 构建的博客如何部署到 github 平台&#xff1f; 1. 新建 github 项目 2. 构建 VitePress 项目 2.1. 设置 config 中的 base 由于我们的项目名称为 vite-press-demo&#xff0c;所以我们把 base 设置为 /vite-press-demo/&#xff0c;需注意前后 / export default…

tidb离线本地安装及mysql迁移到tidb

一、背景&#xff08;tidb8.0社区版&#xff09; 信创背景下不多说好吧&#xff0c;从资料上查tidb和OceanBase“兼容”&#xff08;这个词有意思&#xff09;的比较好。 其实对比了很多数据库&#xff0c;有些是提供云服务的&#xff0c;有些“不像”mysql&#xff0c;综合考虑…

uniapp:K线图,支持H5,APP

使用KLineChart完成K线图制作,完成效果: 1、安装KLineChart npm install klinecharts2、页面中使用 <template><view class="index"><!-- 上方选项卡 --><view class="kline-tabs"><view :style="{color: current==ite…

Windows使用bat远程操作Linux并执行命令

背景&#xff1a;让客户可以简单在Windows中能自己执行 Linux中的脚本&#xff0c;傻瓜式操作&#xff01; 方法&#xff1a;做一个简单的bat脚本&#xff01;能远程连接到Linux&#xff0c;并执行Linux命令&#xff01;客户双击就能使用&#xff01; 1、原先上网查询到使用P…

深度学习:基于Keras框架,使用神经网络模型对葡萄酒类型进行预测分析

前言 系列专栏&#xff1a;机器学习&#xff1a;高级应用与实践【项目实战100】【2024】✨︎ 在本专栏中不仅包含一些适合初学者的最新机器学习项目&#xff0c;每个项目都处理一组不同的问题&#xff0c;包括监督和无监督学习、分类、回归和聚类&#xff0c;而且涉及创建深度学…

《Fundamentals of Power Electronics》——全桥型隔离降压转换器

以下是关于全桥型隔离降压转换器的相关知识点&#xff1a; 全桥变压器隔离型降压转换器如下图所示。 上图展示了一个具有二次侧绕组中心抽头的版本&#xff0c;该电路常用于产生低输出电压。二次侧绕组的上下两个绕组可以看作是两个单独的绕组&#xff0c;因此可以看成是具有变…

CSS-复合选择器

作用&#xff1a; 后代选择器&#xff1a; 子代选择器 并集选择器 用逗号隔开&#xff0c;在style里面写的时候&#xff0c;每一个标签空一行。 <title>Document</title><style>p,div,span{color: aqua;}</style> </head> <body><p>…
最新文章