Kotlin select 选择最快结果

Kotlin select 选择最快结果

概述

  • select是Kotlin 1.6中的特性,即选择最快的结果。
  • select与async、Channel结合使用,可以大大提高程序的响应速度,还可以提高程序的灵活性、扩展性。

使用传统方式

场景:

当需要查询一个商品的详情,如果有缓存先从缓存中读取数据,然后再请求网络获取最新的数据。

data class Product(val productId: String, val price: Double)
suspend fun getCacheInfo(productId: String): Product? {
    delay(100L)
    return Product(productId, 1.1)
}

suspend fun getNetworkInfo(productId: String): Product? {
    delay(200L)
    return Product(productId, 2.2)
}

fun updateUI(product: Product) {
    println("${product.productId} --- ${product.price}")
}
fun main() {
    runBlocking {
        val startTime = System.currentTimeMillis()
        val productId = "12345"
        
        val cacheInfo = getCacheInfo(productId)
        if (cacheInfo != null) {
            updateUI(cacheInfo)
            println("耗时:${System.currentTimeMillis() - startTime}")
        }
        
        val networkInfo = getNetworkInfo(productId)
        if (networkInfo != null) {
            updateUI(networkInfo)
            println("耗时:${System.currentTimeMillis() - startTime}")
        }
    }
}

/*
输出信息:
12345 --- 1.1
耗时:109
12345 --- 2.2
耗时:313
 */

传统方式缺点:先查找缓存的数据,再请求网络,这种串行执行缺乏并发执行优势,并且查找缓存时如果时间过长或发生异常,可能会后续操作。

使用 select & async方式

select 可以配合 async 来使用,async 可以实现并发,select 可以选择最快结果。

select & async 可以解决传统方式的缺点,它可以同时执行多个函数,谁返回的速度快,就会选择谁。

data class Product(
    val productId: String,
    val price: Double,
    val isCache: Boolean = false //判断是否为缓存
)
fun main() {
    runBlocking {
        val startTime = System.currentTimeMillis()
        val productId = "12345"
        val cacheDeferred = async { getCacheInfo(productId) }
        val networkDeferred = async { getNetworkInfo(productId) }
        
        val product = select<Product?> {
            cacheDeferred.onAwait {
                it?.copy(isCache = true)
            }
            networkDeferred.onAwait {
                it?.copy(isCache = false)
            }
        }
        
        if (product != null) {
            updateUI(product)
            println("耗时:${System.currentTimeMillis() - startTime}")
        }
        
        if (product != null && product.isCache) {
            val network = networkDeferred.await() ?: return@runBlocking
            updateUI(network)
            println("耗时:${System.currentTimeMillis() - startTime}")
        }
    }
}

/*
输出信息:
12345 --- 1.1
耗时:125
12345 --- 2.2
耗时:218
 */

说明:使用 async 包裹 getCacheInfo()、getNetworkInfo() 这两个挂起函数,让其实现并发执行,使用 onAwait 将执行结果传给 select,select 才能将数据返回给 product 局部变量。

相比传统方式,总耗时快了很多。

获取最快结果并取消其他Deferred

fun main() = runBlocking {
    val startTime = System.currentTimeMillis()
    suspend fun <T> fastest(vararg deferreds: Deferred<T>): T = select {
        fun cancelAll() = deferreds.forEach { it.cancel() }
        for (deferred in deferreds) {
            deferred.onAwait {
                cancelAll()
                it
            }
        }
    }

    val deferred1 = async {
        delay(100L)
        println("hello 1")
        "world 1"
    }

    val deferred2 = async {
        delay(200L)
        println("hello 2")
        "world 2"
    }

    val deferred3 = async {
        delay(300L)
        println("hello 3")
        "world 3"
    }

    val result = fastest(deferred1, deferred2, deferred3)
    println(result)
    println("耗时: ${System.currentTimeMillis() - startTime}")
}

/*
输出信息:
hello 1
world 1
耗时: 116
 */
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值