web-dev-qa-db-ja.com

Kotlinコルーチン `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
    }
}

データベースを照会するとメインスレッドが停止するので、同期コードと同じ時間がかかるようです。何か足りない場合は修正してください。

10
Angelina

実際には runBlocking を使用して、それ以外の場合は呼び出せない「ブロック」コードで一時停止関数を呼び出します。つまり、コルーチンコンテキストの外でsuspend関数を呼び出します(この例ではasyncに渡されるブロックはsuspend関数です)。また(名前自体がすでに示唆しているように、より明白なことですが)、呼び出しはブロッキング呼び出しです。したがって、例ではasyncのようなものが存在しないかのように実行されます。 runBlocking- block内のすべてが終了するまで(ブロック割り込み可能)待機します。

たとえば、ライブラリ内の関数を次のように仮定します。

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プログラミングのガイド にも興味があるかもしれません。

9
Roland

runBlockingは、同期コードと非同期コードをブリッジする方法です

私はこのフレーズにぶつかり続けており、非常に誤解を招きます。

runBlockingほとんど使用されない本番環境で使用するツールです。これは、コルーチンの非同期、非ブロッキングの性質を取り消します。コルーチンが値を提供しないコンテキストで使用したいコルーチンベースのコードをすでに持っている場合に使用できます:呼び出しのブロック。典型的な用途の1つはJUnitテストで、テストメソッドはただ座ってコルーチンが完了するのを待つ必要があります。

mainメソッド内でコルーチンをいじりながら使用することもできます。

runBlockingの誤用が広まっているため、Kotlinチームは実際にフェイルファーストチェックを追加しようとしました。彼らがこれを行うまでに、すでに多くのコードを壊していたため、削除しなければなりませんでした。

22
Marko Topolnik