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 线程上调用它,它会立即使您的代码崩溃。当他们这样做时,它已经破坏了太多代码,以至于他们不得不将其删除。
我正在学习 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 线程上调用它,它会立即使您的代码崩溃。当他们这样做时,它已经破坏了太多代码,以至于他们不得不将其删除。