Kotlin Coroutines包下的select函数简介

2023-09-18 10:52:41

在工作中,发现了kotlin Coroutines包下有大量功能非常强大的API,这篇文章中,我们主要来聊一聊select函数

1. 什么是select函数

想象一下这个场景,在程序应用中,为了实现一个业务逻辑,你可能有好几种方式来实现,但是我只需要最快实现结果的一种方式,这时候我们就可以使用select函数了。如果还不是很清楚啥意思,我们可以看下图:

最近黄金比较贵,我们的客户端需要实时查询黄金的价格,现在网易服务器和头条服务器都同时提供查询的接口,在同一时间节点上理论上网易服务器和头条服务器返回的数据应该是一样的,我此时同时向网易和头条服务器发送请求数据,那么我此时查询只需要最快返回结果即可。形象一点,我们可以理解为数据的军备竞赛。当然,使用我们现有的知识,完成这个也算是比较容易,使用两个线程然后加上回调即可,但是我来介绍一下如何使用select函数把逻辑做得更优雅一点。

2. 如何使用

来个简单的例子,按照上面的逻辑,我们来查查黄金的价格:

定义两个模拟函数,分别模拟向网易和头条获取黄金数据:

private suspend fun requestNestGoldData() = withContext(Dispatchers.IO){
        Log.d("select","start to request nest gold data")
        delay(100)

        Log.d("select","get the nest gold data success")
        "nest_" + 600.00
}

private suspend fun requestByteDanceData() = withContext(Dispatchers.IO) {
        Log.d("select","start to request byte dance gold data")
        delay(300)

        Log.d("select","get the nest gold byte dance success")
        "bytedance_" + 600.00
}

然后我们使用select函数进行绑定并获取数据:

viewModelScope.launch {

  val requestDataResult = select {

     async { requestNestGoldData() }.onAwait { it }

     async { requestByteDanceData() }.onAwait { it }

   }

   Log.d("select","get the result : $requestDataResult")
}

然后我们来看一下打印日志:

2023-09-17 15:54:23.164 19063-19188 select   D  start to request nest gold data
2023-09-17 15:54:23.164 19063-19189 select   D  start to request byte dance gold data
2023-09-17 15:54:23.266 19063-19188 select   D  get the nest gold data success
2023-09-17 15:54:23.449 19063-19063 select   D  get the result : nest_600.0
2023-09-17 15:54:23.466 19063-19188 select   D  get the nest gold byte dance success

通过日志我们发现,我们的requestNestGoldData()requestByteDanceData()同时进行了请求,但是select的结果中只返回了最快的结果,当然速度慢的接口依然还在执行,只是结果丢弃了。

3. 后续

如果我们使用 回调应该怎么做呢?不妨来写一写它的伪代码实现:

interface ResultListener {
  
  fun onResult(info String)
 
}

private suspend fun requestNestGoldDataWithListener(listner : Resultlistener) {
        runBlocking(Dispatchers.IO){
            Log.d("select","start to request nest gold data")
            delay(100)

            Log.d("select","get the nest gold data success")
            listner.onResult("nest_" + 600.00)
        }
}

private suspend fun requestByteDanceGoldDataWithListener(listner : Resultlistener) {
        runBlocking(Dispatchers.IO){
            Log.d("select","start to request byte dance gold data")
            delay(100)

            Log.d("select","get the nest byte dance data success")
            listner.onResult("nest_" + 600.00)
        }
}


viewModelScope.launch {
  
  var hasResult : Boolean = false 

	val listener : ResultListener = object : ResultListener {
    	override 	fun onResult(info String){
        	if(!hasResult) {
            hasResult = true 
            //deal with the result
          }
      }
  }
  
  requestNestGoldDataWithListener(listener)
  requestByteDanceGoldDataWithListener(listener
}

伪代码出来了,可以看出,过程还是十分容易的,此时可能还不能看出使用回调和select的区别,但是如果我们同时存在5条链路进行数据请求时,此时我们就可以看到select的简洁和强大。

更多推荐

C# 流Stream详解(3)——FileStream源码

【FileStream】构造函数如果创建一个FileStream,常见的参数例如路径Path、操作方式FileMode、权限FileAccess。这里说下FileShare和SafeFileHandle。我们知道在读取文件时,通常会有两个诉求:一是如何更快的读取文件内容;二是如何减少读取文件的消耗。常见的加快读取文件的

在ubuntu20.04中创建虚拟机:Oracle VirtualBox - 7中安装Windows-10(64bit)

问题描述之前一直在用ubuntu20.04,但是今天遇到一个需求:需要判定.exe文件是否可以正常运行,这样一来可能就需要一个虚拟机来佐助了,当然也搜了一些其他的处理办法,但是我大概看了一下,并不能满足我的需求。如果有需要请看:linux下如何完美运行exe文件?https://www.zhihu.com/questi

C#实现异步方式

在异步程序中,程序代码不需要严格按照编写时的顺序执行为了改善代码性能,有时候需要在一个新的线程中运行一部分代码有时候无需创建新的线程,但为了更好的利用单个线程的能力,需要改变代码的执行顺序也就是说:异步编程赋予代码非顺序执行的能力,让程序能够在部分耗时操作的同时,干其他的事情一、通过委托实现异步如果委托对象在调用列表中

【LeetCode-困难题】239. 滑动窗口最大值

文章目录题目方法一:单调双端队列题目方法一:单调双端队列if(deque.peekFirst()==nums[i-k])deque.removeFirst();这一步很关键,当队首元素(最大元素)是滑动窗口后要被抛弃的元素时,他就不能再是最大值了,就必须去掉,如果队首元素(最大元素)不是滑动窗口被抛弃的元素,则继续充当

linux部署页面内容

/bin:该目录包含了常用的二进制可执行文件,如ls、cp、mv、rm等等。/boot:该目录包含了启动Linux系统所需的文件,如内核文件和引导加载程序。/dev:该目录包含了所有设备文件,如硬盘、光驱、鼠标、键盘等等。/etc:该目录包含了系统的配置文件,如网络配置、用户账户、安全设置等等。/home:该目录是所有

PT@Bernoulli概型@古典概型之伯努利概型

文章目录abstract伯努利概型伯努利试验n重伯努利试验例样本空间样本空间的重要划分成功k次的n重Bernoulli试验例例例abstractBernoulli概型是结合独立事件和n重Bernoulli试验概念的古典概型伯努利概型Bernoulli概型是基于bernoulli试验的一类古典概型这类概型的等可能性体现在

定时任务框架-xxljob

1.定时任务spring传统的定时任务@Scheduled,但是这样存在这一些问题:做集群任务的重复执行问题cron表达式定义在代码之中,修改不方便定时任务失败了,无法重试也没有统计如果任务量过大,不能有效的分片执行解决这些问题的方案为:xxl-job分布式任务调度框架2.分布式任务调度2.1什么是分布式任务调度当前软

R语言贝叶斯非参数模型:密度估计、非参数化随机效应META分析心肌梗死数据...

全文链接:http://tecdat.cn/?p=23785最近,我们使用贝叶斯非参数(BNP)混合模型进行马尔科夫链蒙特卡洛(MCMC)推断(点击文末“阅读原文”获取完整代码数据)。概述相关视频在这篇文章中,我们通过展示如何使用具有不同内核的非参数混合模型进行密度估计。在后面的文章中,我们将采用参数化的广义线性混合模

idea快捷键

目录前言一.Ctrl相关二.Alt相关三.Shift相关四.Ctrl+Alt相关五.Ctrl+Shift相关六.Alt+Shift相关七.其他汇总前言IDEA中提供了很多快捷键,点击File-->Settings-->keymap便可进入看到IDEA提供的快捷键。我们也可以搜索和自定义所有快捷键,下面给出的是IDEA中

uniapp瀑布流布局写法

首先我们要清楚瀑布流是什么?瀑布流布局(WaterfallFlowLayout),也称为瀑布流式布局,是一种常见的网页或移动应用布局方式,特点是元素以不规则的方式排列,就像瀑布中的流水一样,每个元素的高度可以不同。主要特点和优点包括:不规则的排列:瀑布流布局允许元素以不同的高度和宽度排列,因此适用于展示不同尺寸和形状的

网络安全(黑客)自学

想自学网络安全(黑客技术)首先你得了解什么是网络安全!什么是黑客网络安全可以基于攻击和防御视角来分类,我们经常听到的“红队”、“渗透测试”等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。无论网络、Web、移动、桌面、云等哪个领域,都有攻与防两面性,例如Web安全技术,既有Web渗透,也有Web

热文推荐