首页 > 其他分享 >【Kotlin】select简介

【Kotlin】select简介

时间:2024-12-08 12:21:23浏览次数:7  
标签:suspend invoke Kotlin select 简介 fun public block

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简介

标签:suspend,invoke,Kotlin,select,简介,fun,public,block
From: https://www.cnblogs.com/zhyan8/p/18592835

相关文章

  • PCIe扫盲——PCIe简介
    PCI-Express是继ISA和PCI总线之后的第三代I/O总线,即3GIO。由Intel在2001年的IDF上提出,由PCI-SIG(PCI特殊兴趣组织)认证发布后才改名为“PCI-Express”。它的主要优势就是数据传输速率高,另外还有抗干扰能力强,传输距离远,功耗低等优点。注:第一代总线一般指ISA、EISA、VESA和MicroPla......
  • 快速入睡:如何获得一夜好眠0简介
    0简介睡眠是我们每个人都会做的事情;事实上,我们一生中大约有三分之一的时间是在这种奇怪的无意识状态中度过的。然而,直到最近,我们对睡眠的作用、我们需要多少睡眠以及梦在改善心理健康方面的作用仍然知之甚少。好消息是,在过去的20年里,我们对睡眠以及睡眠的重要性的认识发生了......
  • 写一个 document.querySelector 的逆方法
    functionquerySelectorAllReverse(selector){constelements=document.querySelectorAll(selector);returnArray.from(elements).reverse();}//Exampleusage://AssumingyourHTMLcontains://<divclass="my-element">1</div>/......
  • Kotlin设计模式之单例模式
    一.使用object关键字Kotlin提供了object关键字来直接创建单例对象,这是最简单和推荐的方式。//SingletonObject.ktobjectSingletonObject{fundoSomething(){println("Doingsomething...")}}二.使用companion objectcompanion object可以用于......
  • API接口简介:让前后端无缝沟通
    背景介绍:在今天的互联网世界,前后端分离的架构已经成为常态,而在这其中,API接口的作用至关重要。作为前后端沟通的桥梁,API接口确保了数据的顺利传递和业务逻辑的执行。而很多刚入门的编程爱好者可能跟我刚开始学习一样对这个概念一知半解,现在,我们就来聊聊API接口,它是如何工作的,以......
  • k8s~service和deployment中的spec.selector
    service和deployment中的spec.selector在Kubernetes中,Service和Deployment的spec.selector在使用上是有一些不同之处的,下面是对这两者的详细解释:1.Deployment中的Selector在Deployment中,spec.selector是必需的,并且通常使用matchLabels来定义选择器。例如:apiVer......
  • Go语言简介:新时代的高效编程语言
    一、什么是Go语言?Go语言(又称Golang)是一种由Google开发的开源编程语言,于2009年首次发布。它的主要设计目标是提供高效、简单和可靠的编程体验,同时结合静态类型语言的安全性和动态语言的开发效率。Go语言因其简洁的语法、内置并发支持和高性能而备受开发者青睐。1.1背景与......
  • Voxposer简介
    VoxPoserisaframeworkthatleverageslargelanguagemodels(LLMs)andvision-languagemodels(VLMs, orVision-LanguageModels,areaclassofartificialintelligencemodelsdesignedtoprocessandintegratevisualandtextualinformation.Thesemodelsa......
  • 北京泽元堂王世龙简介,如何预约及流程
    王世龙预约拨打:|78 |2○8 5○44王世龙,男,现北京泽元堂中医主治医师,毕业于河北医科大学。从医将近25年,擅长治疗于神经系统方面疾病,以一人一方辨证施治的方式进行调理治疗:帕金森病、植物神经紊乱(头晕头痛、焦虑抑郁)、特发性震颤、重症肌无力、运动神经元病、耳鸣等等。王世......
  • jQuery和css3超赞select下拉列表框美化插件
    这是一款效果超赞的jQuery和css3select下拉列表框美化插件。这个select下拉列表框插件没有使用任何的图片,纯css制作,还使用了一点jQuery来完成动作交互。在线演示 下载 有两个地方需要做下说明:下面的代码中没有使用任何厂商的前缀。在插件中使用了CSS盒子模式(box-model):......