Angelina
Estoy aprendiendo rutinas de Kotlin. he leido eso runBlocking
es la forma de unir el código sincrónico y asincrónico. Pero, ¿cuál es la ganancia de rendimiento si el runBlocking
detiene el hilo de la interfaz de usuario? Por ejemplo, necesito consultar una base de datos en 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
}
}
Consultar la base de datos detendría el hilo principal, por lo que parece que tomaría la misma cantidad de tiempo que el código síncrono. Por favor corrígeme si me estoy perdiendo algo.
Marko Topolnik
runBlocking
es la forma de unir el código síncrono y asíncrono
Sigo topándome con esta frase y es muy engañosa.
runBlocking
es casi nunca una herramienta que utiliza en la producción. Deshace la naturaleza asincrónica y no bloqueante de las rutinas. Puede usarlo si ya tiene algún código basado en rutinas que desea usar en un contexto donde las rutinas no brindan ningún valor: en el bloqueo de llamadas. Un uso típico es la prueba JUnit, donde el método de prueba simplemente debe esperar a que se complete la rutina.
También puedes usarlo mientras juegas con rutinas, dentro de tu main
método.
el mal uso de runBlocking
se ha generalizado tanto que el equipo de Kotlin en realidad intentó agregar una verificación rápida que bloquearía inmediatamente su código si lo llama en el subproceso de la interfaz de usuario. Cuando hicieron esto, ya estaba rompiendo tanto código que tuvieron que eliminarlo.
-
el mal uso de
runBlocking
se ha generalizado tanto que el equipo de Kotlin ha tenido que revertir el cambio con fail-fast 🙂– qwwdfsad
14/09/2018 a las 15:35
-
Esta explicación de revertir fallas rápidamente es en realidad engañosa, no es solo un problema de un mal uso (que definitivamente existe), el problema fue que hay casos de uso válidos, como el inicio de la aplicación, la limpieza de recursos, etc. rastreador de problemas, solución con parámetro adicional “sí, bloque, sé lo que estoy haciendo, por favor no bloquee” no sería mejor en mi opinión. Un problema más fue que falló en el código de lanzamiento, pero no en la depuración, que es una estrategia incorrecta que causa errores, no los previene.
– dorador
10 mayo 2019 a las 15:42
-
¿Qué se debe usar en lugar de runBlocking para llamar coroutines sin bloquear?
– Trevor
14 de noviembre de 2019 a las 21:56
-
@Trevor Deberías
launch
una rutina.– Marko Topolnik
15 de noviembre de 2019 a las 7:15
-
@usuario3410835
runBlocking
devuelve el resultado de la rutina que inicia, lo que significa que debe esperar a que se complete.– Marko Topolnik
24 de mayo de 2020 a las 17:13
roland
en realidad usas runBlocking
para llamar a funciones de suspensión en código de “bloqueo” que de otro modo no se podría llamar allí o en otras palabras: lo usa para llamar suspend
funciones fuera del contexto coroutine (en su ejemplo, el bloque pasó a async
es el suspend
función). Además (más obvio, como ya implica el propio nombre), la llamada es una llamada de bloqueo. Entonces, en su ejemplo, se ejecuta como si no hubiera algo como async
en su lugar. espera (bloquea interrumpiblemente) hasta que todo dentro del runBlocking
-el bloque está terminado.
Por ejemplo, suponga una función en su biblioteca de la siguiente manera:
suspend fun demo() : Any = TODO()
Este método no sería invocable desde, por ejemplo main
. Para tal caso se utiliza runBlocking
entonces, por ejemplo:
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
}
Con respecto a la ganancia de rendimiento: en realidad, su aplicación puede ser más receptiva en lugar de tener más rendimiento (a veces también más rendimiento, por ejemplo, si tiene varias acciones paralelas en lugar de varias secuenciales). En su ejemplo, sin embargo, ya bloquea cuando asigna la variable, por lo que diría que su aplicación aún no responde mejor. Es posible que desee llamar a su consulta de forma asincrónica y luego actualizar la interfaz de usuario tan pronto como la respuesta esté disponible. Así que básicamente simplemente omites runBlocking
y más bien usar algo como launch
. Usted también podría estar interesado en Guía de programación de interfaz de usuario con rutinas.
-
¿Podría explicar qué significa “llamar a las funciones de suspensión fuera del contexto coroutine”. ¿significar? quiere decir que suspender está fuera del
runBlocking
¿contexto? Estoy de acuerdo, pero elrunBlocking
regresaría solo después de que regrese la función de suspensión, por lo que no hay ganancia de velocidad en mi opción. La única diferencia es que la consulta se ejecuta en un hilo diferente– angelina
14 de septiembre de 2018 a las 12:02
-
agregó una muestra de lo que quiero decir… si no está claro, solo pregunte
– roland
14 de septiembre de 2018 a las 12:06
-
tenga en cuenta también que para los casos en los que realmente desea ejecutar de forma asíncrona, no utiliza
runBlocking
…– roland
14 de septiembre de 2018 a las 12:07
-
actualicé un poco mi respuesta … también con respecto a la ganancia de rendimiento … tenga en cuenta que su código actual es casi el mismo que una variante síncrona sin rutinas … solo intente omitir
runBlocking
y uselaunch
y básicamente experimentas la llamada asíncrona 😉– roland
14 de septiembre de 2018 a las 12:36
-
Gracias por esto más fácil de entender que la documentación.
– dave o grady
26 de diciembre de 2019 a las 23:51