如何使用Kotlin协程调用阻塞函数?

时间:2020-10-11 16:25:09

标签: kotlin kotlin-coroutines

我想使用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将阻止流“转换”为协程流的角度来看:

  1. 是否有标准或更好的方法来做到这一点?
  2. 除了网络或性能之外-您认为我的方法有什么缺点吗?

2 个答案:

答案 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的更多信息。