Kotlin 协程 `runBlocking`

Kotlin coroutines `runBlocking`

我正在学习 Kotlin 协程。我读过 runBlocking 是桥接同步和异步代码的方法。但是,如果 runBlocking 停止 UI 线程,性能增益是多少? 比如我需要查询一个数据库在Android:

    val result: Int
    get() = runBlocking { queryDatabase().await() }

private fun queryDatabase(): Deferred<Int> {
    return async {
        var cursor: Cursor? = null
        var queryResult: Int = 0
        val sqlQuery = "SELECT COUNT(ID) FROM TABLE..."
        try {
            cursor = getHelper().readableDatabase.query(sqlQuery)
            cursor?.moveToFirst()
            queryResult = cursor?.getInt(0) ?: 0
        } catch (e: Exception) {
            Log.e(TAG, e.localizedMessage)
        } finally {
            cursor?.close()
        }
        return@async queryResult
    }
}

查询数据库会停止主线程,所以它似乎与同步代码花费相同的时间?如果我遗漏了什么,请纠正我。

实际上,您使用 runBlocking 来调用“阻塞”代码中的挂起函数,否则将无法在那里调用,或者换句话说:您使用它来调用 suspend 协程之外的函数上下文(在您的示例中,传递给 async 的块是 suspend 函数)。此外(更明显,顾名思义),调用 then 是一个阻塞调用。因此,在您的示例中,它的执行就像没有 async 之类的东西一样。它等待(块中断)直到runBlocking块内的所有内容都完成。

例如,假设您的库中有一个函数如下:

suspend fun demo() : Any = TODO()

此方法不能从例如main。对于这种情况,您可以使用 runBlocking,例如:

fun main(args: Array<String>) {
  // demo() // this alone wouldn't compile... Error:() Kotlin: Suspend function 'demo' should be called only from a coroutine or another suspend function
  // whereas the following works as intended:
  runBlocking {
    demo()
  } // it also waits until demo()-call is finished which wouldn't happen if you use launch
}

关于性能提升:实际上您的应用程序可能宁愿响应更快而不是性能更高(有时性能也更高,例如,如果您有多个并行操作而不是几个顺序操作)。但是,在您的示例中,您在分配变量时已经阻塞,所以我会说您的应用程序还没有获得更快的响应。您可能更愿意异步调用您的查询,然后在响应可用时立即更新 UI。所以你基本上只是省略 runBlocking 而使用 launch 之类的东西。您可能还对 Guide to UI programming with coroutines.

感兴趣

runBlocking is the way to bridge synchronous and asynchronous code

我经常碰到这个短语,它非常具有误导性。

runBlocking 几乎从不 是您在生产中使用的工具。它取消了协程的异步、非阻塞特性。如果你碰巧已经有一些基于协程的代码,你想在协程不提供任何价值的上下文中使用它,你可以使用它:在阻塞调用中。一种典型的用途是 JUnit 测试,其中测试方法必须等待协程完成。

您也可以在 main 方法中使用协程来使用它。

runBlocking 的滥用变得如此普遍,以至于 Kotlin 团队实际上试图添加一个快速失败检查,如果您在 UI 线程上调用它,它会立即使您的代码崩溃。当他们这样做时,它已经破坏了太多代码,以至于他们不得不将其删除。