![](/img/trans.png)
[英]Kotlin coroutines unit testing with runBlocking does not wait for execution
[英]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
是桥接同步和异步代码的方法
我一直在碰到这句话,这是非常误导的。
runBlocking
几乎从不是您在生产中使用的工具。 它解除了协同程序的异步,非阻塞性质。 如果你碰巧已经有一些基于协同程序的代码,你想在协同程序没有提供任何价值的上下文中使用它,你可以使用它:阻塞调用。 一个典型的用途是JUnit测试,其中测试方法必须坐下并等待协程完成。
您也可以在main
方法中使用协同程序时使用它。
滥用runBlocking
已经变得如此普遍,以至于Kotlin团队实际上试图添加一个快速失败检查,如果你在UI线程上调用它会立即崩溃你的代码。 当他们这样做时,已经打破了这么多代码,他们不得不删除它。
实际上你使用runBlocking
来调用“阻塞”代码中的暂停函数,否则这些代码将无法在那里调用或者换句话说:你用它来调用协同程序上下文之外的suspend
函数(在你的例子中,传递给async
的块是suspend
功能)。 此外(更明显的是,正如名称本身所暗示的那样),然后呼叫是阻塞呼叫。 因此,在您的示例中,它被执行就好像没有像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
这样的东西。 您可能还对使用协同程序进行UI编程指南感兴趣。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.