多路复用
await 多路复用
两个API分别从网络和本地缓存取数据,期望哪个先返回就先用哪个
private val filePath = "xxx"
private val gson = Gson()
data class Response<T>(val value:T, val isLocal:Boolean)
fun CoroutineScope.getUserFromLocal(name:String) = async(Dispatchers.IO){
delay(1000)
File(filePath).readText().let { gson.fromJson(it, User::class.java) }
}
fun CoroutineScope.getUserFromRemote(name:String) = async(Dispatchers.IO){
userServiceApi.getUser(name)
}
/**
* @desc: 多路复用和并发
*/
class CoroutineTest5 {
@Test
fun `test select` ()= runBlocking<Unit>{
GlobalScope.launch {
val localRequest = getUserFromLocal("xxx")
val remoteRequest = getUserFromRemote("yyy")
val userResponse = select<Response<User>> {
localRequest.onAwait{Response(it, true)}
remoteRequest.onAwait{Response(it, false)}
}
userResponse.value?.let { println(it) }
}.join()
}
}
select会返回最先返回的Response
多路复用channel
@Test
fun `test select channel` ()= runBlocking<Unit>{
val channels = listOf(Channel<Int>(), Channel<Int>())
GlobalScope.launch {
delay(200)
channels[0].send(200)
}
GlobalScope.launch {
delay(100)
channels[1].send(100)
}
val result = select<Int?> {
channels.forEach{channel ->
channel.onReceive{it}
}
}
//会输出较快的那个,也就是100
println(result)
}
哪些事件可以被select
-
能被select的事件都是SelectClauseN类型
-
要确认挂起函数是否支持select,只需要查看其是否存在对应得SelectClauseN类型可回调即可
flow实现多路复用
//最终2个结果都会输出
@Test
fun `test select flow` ()= runBlocking<Unit>{
//模拟实现多路复用
//函数->协程->flow->flow合并
val name = "guest"
coroutineScope {
listOf(::getUserFromLocal, ::getUserFromRemote)
.map { function-> function.call(name)}//遍历调用
.map { deferred-> flow { emit(deferred.await()) } }
.merge()//多个flow合并成一个flow
.collect { user->//末端操作符
println("result:$user")
println("collect")
}
}
}
并发安全
协程的并发工具
-
Channel:并发安全的消息通道
-
Mutex:轻量级的锁,它的lock和unlock从语义上和线程锁比较类似,之所以轻量,是因为它在获取不到锁时不会阻塞线程,而是挂起等待锁的释放
-
Semaphore:轻量级信号量,信号量可以有多个,协程在获取到信号量后即可执行并发操作。当semaphore的参数为1时,效果等价于Mutex
@Test
fun test safe concurrent tools ()= runBlocking{
var count = 0
val mutex = Mutex()
List(100){
GlobalScope.launch {
mutex.withLock {
count++
}
}
}.joinAll()
println(count)
}
👀关注公众号:Android老皮!!!欢迎大家来找我探讨交流👀