Kotlin-Koroutinen „runBlocking“.

Lesezeit: 5 Minuten

Angelinas Benutzeravatar
Angelina

Ich lerne Kotlin-Koroutinen. Ich habe das gelesen runBlocking ist der Weg, synchronen und asynchronen Code zu überbrücken. Aber was ist der Leistungsgewinn, wenn die runBlocking stoppt den UI-Thread? Zum Beispiel muss ich eine Datenbank in Android abfragen:

    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
    }
}

Das Abfragen der Datenbank würde den Hauptthread stoppen, also würde es anscheinend genauso lange dauern wie synchroner Code? Bitte korrigieren Sie mich, wenn ich etwas übersehe.

Benutzeravatar von Marko Topolnik
Marco Topolnik

runBlocking ist der Weg, synchronen und asynchronen Code zu überbrücken

Ich stoße immer wieder auf diesen Satz und er ist sehr irreführend.

runBlocking ist fast nie ein Werkzeug, das Sie in der Produktion verwenden. Es macht die asynchrone, nicht blockierende Natur von Coroutinen rückgängig. Sie können es verwenden, wenn Sie bereits Coroutine-basierten Code haben, den Sie in einem Kontext verwenden möchten, in dem Coroutinen keinen Wert bieten: beim Blockieren von Aufrufen. Eine typische Verwendung ist das JUnit-Testen, bei dem die Testmethode einfach warten muss, bis die Coroutine abgeschlossen ist.

Sie können es auch verwenden, während Sie mit Koroutinen in Ihrem herumspielen main Methode.

Der Missbrauch von runBlocking ist so weit verbreitet, dass das Kotlin-Team tatsächlich versuchte, eine Fail-Fast-Prüfung hinzuzufügen, die Ihren Code sofort zum Absturz bringen würde, wenn Sie ihn im UI-Thread aufrufen. Als sie dies taten, war bereits so viel Code kaputt, dass sie ihn entfernen mussten.

  • Der Missbrauch von runBlocking ist so weit verbreitet, dass das Kotlin-Team Änderungen mit Fail-Fast rückgängig machen musste 🙂

    – qwwdfsad

    14. September 2018 um 15:35 Uhr

  • Diese Erklärung von Revert Fail-Fast ist eigentlich irreführend, es ist nicht nur das Problem einer Fehlbedienung (die definitiv existiert), das Problem war, dass es gültige Anwendungsfälle gibt, wie z. B. Anwendungsstart, Ressourcenbereinigung usw. Sie können eine Diskussion darüber in Coroutinen sehen Issue-Tracker, Lösung mit zusätzlichem Parameter “ja, block, ich weiß was ich tue, bitte nicht abstürzen” wäre imo nicht besser. Ein weiteres Problem war, dass es beim Release-Code fehlschlug, aber nicht beim Debuggen, was eine falsche Strategie ist, die Fehler verursacht, nicht verhindert

    – Vergolder

    10. Mai 2019 um 15:42 Uhr


  • Was sollte anstelle von runBlocking verwendet werden, um Coroutinen ohne Blockierung aufzurufen?

    – Trevor

    14. November 2019 um 21:56 Uhr

  • @ Trevor Du solltest launch eine Koroutine.

    – Marko Topolnik

    15. November 2019 um 7:15 Uhr

  • @ user3410835 runBlocking gibt das Ergebnis der von ihr gestarteten Coroutine zurück, was bedeutet, dass sie warten muss, bis sie abgeschlossen ist.

    – Marko Topolnik

    24. Mai 2020 um 17:13 Uhr

Benutzeravatar von Roland
Roland

Eigentlich benutzt du runBlocking um suspendierende Funktionen in “blockierendem” Code aufzurufen, die sonst dort nicht aufrufbar wären, oder mit anderen Worten: Sie verwenden es zum Aufrufen suspend Funktionen außerhalb des Coroutine-Kontexts (in Ihrem Beispiel der Block, an den übergeben wird async ist der suspend Funktion). Außerdem (offensichtlicher, wie der Name schon sagt) ist der Anruf dann ein blockierender Anruf. In Ihrem Beispiel wird es also so ausgeführt, als ob es so etwas nicht gäbe async an Ort und Stelle. Es wartet (blockt unterbrechbar) bis alles innerhalb der runBlocking-Block ist fertig.

Nehmen Sie zum Beispiel eine Funktion in Ihrer Bibliothek wie folgt an:

suspend fun demo() : Any = TODO()

Diese Methode wäre z. B. nicht aufrufbar main. Für einen solchen Fall verwenden Sie runBlocking dann zB:

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
}

Apropos Performance-Gewinn: Tatsächlich ist Ihre Anwendung möglicherweise eher reaktionsschneller als performanter (manchmal auch performanter, z. B. wenn Sie mehrere parallele Aktionen anstelle mehrerer sequentieller Aktionen haben). In Ihrem Beispiel blockieren Sie jedoch bereits, wenn Sie die Variable zuweisen, sodass ich sagen würde, dass Ihre App noch nicht reaktionsschneller wird. Möglicherweise möchten Sie Ihre Abfrage lieber asynchron aufrufen und dann die Benutzeroberfläche aktualisieren, sobald die Antwort verfügbar ist. Also lässt du es im Grunde einfach weg runBlocking und verwenden Sie lieber so etwas wie launch. Das könnte Sie auch interessieren Leitfaden zur UI-Programmierung mit Coroutinen.

  • könnten Sie bitte erklären, was “Suspend-Funktionen außerhalb des Coroutine-Kontexts aufruft”. bedeuten? Du meinst, dass Suspend außerhalb des ist runBlocking Kontext? Ich stimme zu, aber die runBlocking würde erst zurückkehren, nachdem die Suspend-Funktion zurückkehrt, daher gibt es in meiner Option keinen Geschwindigkeitsgewinn. Der einzige Unterschied besteht darin, dass die Abfrage in einem anderen Thread ausgeführt wird

    – Angelina

    14. September 2018 um 12:02 Uhr


  • Beispiel hinzugefügt was ich meine … wenn es nicht klar ist, einfach fragen

    – Roland

    14. September 2018 um 12:06 Uhr

  • Beachten Sie auch, dass Sie in Fällen, in denen Sie tatsächlich asynchron laufen möchten, nicht verwenden runBlocking

    – Roland

    14. September 2018 um 12:07 Uhr

  • meine Antwort ein wenig aktualisiert … auch in Bezug auf den Leistungsgewinn … beachten Sie, dass Ihr aktueller Code eigentlich fast derselbe ist wie eine synchrone Variante ohne Coroutinen … versuchen Sie es einfach wegzulassen runBlocking und verwenden launch und Sie erleben im Grunde den asynchronen Aufruf 😉

    – Roland

    14. September 2018 um 12:36 Uhr

  • Danke, dass dies einfacher zu verstehen ist als die Dokumentation

    – dave o grady

    26. Dezember 2019 um 23:51 Uhr

1435800cookie-checkKotlin-Koroutinen „runBlocking“.

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy