0
点赞
收藏
分享

微信扫一扫

Kotlin select 选择最快结果

Python百事通 2022-04-02 阅读 53

文章目录

Kotlin select 选择最快结果

概述

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

select & async

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

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

传统方式

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可以解决传统方式的缺点,它可以同时执行多个函数,谁返回的速度快,就会选择谁。

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 = true)
            }
        }
        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
 */

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

获取最快结果,取消其他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("Time cost: ${System.currentTimeMillis() - startTime}")
}

/*
输出信息:
hello 1
world 1
Time cost: 116
 */
举报

相关推荐

0 条评论