Kotlin多路复用

54 阅读1分钟

await多路复用

两个API网络和本地获取数据,期望哪个先返回就用哪个:

// 多路复用,谁先返回使用谁
fun test() = runBlocking {
    GlobalScope.launch {
        val local = getUserFromLocal("george")
        val net = getUserFromNet("george")
        val result = select<String> {
            local.onAwait{it}
            net.onAwait{it}
        }
        // 最终使用哪个,看哪个先返回
        result.let {
            Log.d(TAG, "test: $it")
        }
    }.join()
}

fun CoroutineScope.getUserFromLocal(name:String)=async(Dispatchers.IO) {
    delay(300)
    "${name}read Local"
}

fun CoroutineScope.getUserFromNet(name:String)=async(Dispatchers.IO) {
    delay(200)
    "${name}read Net"
}

select会返回最先返回的数据

多路复用channel

fun test2() = runBlocking {
    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
    Log.d(TAG, "result:$result")
}

flow实现多路复用

fun test3() = runBlocking {
    //模拟实现多路复用
    //函数->协程->flow->flow合并
    val name = "guest"
    coroutineScope {
        listOf(
            async { getUserFromLocal(name).await() }, // 使用async直接执行
            async { getUserFromNet(name).await() }
        )
            .map { deferred -> flow { emit(deferred.await()) } }
            .merge() //多个flow合并成一个flow
            .collect { user -> //末端操作符
                Log.d(TAG,"result:$user")
            }
    }
}

fun CoroutineScope.getUserFromLocal(name: String) = async(Dispatchers.IO) {
    delay(300)
    "${name} read Local"
}

fun CoroutineScope.getUserFromNet(name: String) = async(Dispatchers.IO) {
    delay(200)
    "${name} read Net"
}

两个结果都会通过collect输出,耗时最短的先输出。

Mutex并发安全

// 按照顺序打印出count。如果不使用Mutex,会发现值跳跃(例如:5->7->6)
fun test4(){
    runBlocking {
        var count = 0
        val mutex = Mutex()
        List(100){
            GlobalScope.launch {
                mutex.withLock {
                    count++
                    Log.d(TAG,"countAdd:$count")
                }
            }
        }.joinAll()
        Log.d(TAG,"count:$count")
    }
}

Mutex轻量级锁,lock和unlock,在获取不到锁时不会阻塞线程,而是挂起等待锁的释放。