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}")
}
}
}
传统方式的问题:先查找缓存的数据,再请求网络,这种串行执行缺乏并发执行优势,并且查找缓存时如果时间过长或发生异常,可能会后续操作。
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}")
}
}
}
说明:相比传统方式,总耗时快了很多。
获取最快结果,取消其他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}")
}
|