我想用Kotlin协同器来调用阻塞函数。
例如,我希望有一个挂起函数,它将“阻塞”直到用户响应一个模态对话框,或者直到一个网络调用返回时,当对话框和网络库不提供suspend函数时。
我使用Mutex实现了它。
例如,对于阻塞网络调用场景,我执行了如下操作:
class Connection {
private val mutex = Mutex()
public suspend fun receive(): ByteArray {
mutex.lock()
val buf = ByteArray(42)
thread {
sock.getInputStream().read(buf, 0, 42) // blocking
mutex.unlock()
}
mutex.lock()
return buf
}
}它起作用了。
请忽略上述代码中与网络相关的问题(如错误处理、检查实际读取的字节数等)。
还请忽略使用线程的性能方面(上面的专用线程只是为了示例)。
从使用Mutex将阻塞流“转换”为协同流的角度来看:
发布于 2020-10-11 16:56:14
你可以这样做:
suspend fun receive(): ByteArray {
return withContext(Dispatchers.IO) {
val buf = ByteArray(42)
sock.getInputStream().read(buf, 0, 42) // blocking
buf
}
}从您的Activity中调用它为:
lifecycleScope.launch{
withContext(Dispatchers.Main) {
//showLoading
val result = receive()
//hideloading
}
}接收函数将在IO dispatcher (即designed for offloading blocking IO tasks to a shared pool of threads )中运行,请参阅有关dispatcher 这里的更多信息。
发布于 2020-10-11 16:55:18
标准的方法是使用IO调度器,它被设计为有大量线程池来处理阻塞操作(顾名思义,IO)。
withContext(Dispatchers.IO) {
sock.getInputStream().read(buf, 0, 42)
}这将暂停协同线,直到阻塞操作完成。
您的方法的缺点是,执行的顺序并不完全清楚,而且容易出现死锁。例如,如果阻塞调用抛出异常,互斥锁永远不会解锁,协同线将被卡住。此外,它还为每个阻塞操作创建新线程,而IO dispatcher则设计为重用一个线程池以避免这种开销。
https://stackoverflow.com/questions/64306381
复制相似问题