我想使用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
将阻止流“转换”为协程流的角度来看:
答案 0 :(得分:3)
标准方法是使用IO
调度程序,该调度程序被设计为具有大量线程来处理阻塞操作(顾名思义,IO)。
withContext(Dispatchers.IO) {
sock.getInputStream().read(buf, 0, 42)
}
这将暂停协程直到阻塞操作完成。
该方法的缺点是执行顺序不完全清楚,容易陷入僵局。例如,如果您的阻塞呼叫引发异常,则互斥锁永远不会解锁,协程将被卡住。此外,它为每个阻塞操作都创建了新线程,而IO调度程序旨在重用线程池以避免这种开销。
答案 1 :(得分:3)
您可以这样做:
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
}
}
receive函数将在IO调度程序中运行,该调度程序是designed for offloading blocking IO tasks to a shared pool of threads
,有关调度程序here的更多信息。