Kotlin coroutinesのasyncが動かない?

はじめに

KotlinでCoroutinesを使うときにAsync awaitを使って処理の待ち合わせをするケースがあります。 そのときに非同期処理が期待どおりに動かなかったことがあるので、記録として書いておきます。

状況

ソースにしたほうが早いので以下にソースを書きます。

ソース

import kotlinx.coroutines.*

/**
 * 意図した動きをしないasyncのサンプル
 * すべてメインthreadで動いている
 */
fun main(args: Array<String>) = runBlocking {
    val resultADeferred = methodA()
    val resultBDeferred = methodB()
    println("${resultADeferred.await()},${resultBDeferred.await()}")
}

private suspend fun methodA() = coroutineScope {
    async {
        println("beforeA")
        delay(1000)
        println("afterA")
        "result A"
    }
}

private suspend fun methodB() = coroutineScope {
    async{
        println("beforeB")
        delay(3000)
        println("afterB")
        "result B"
    }
}

結果

以下の順番に出力されるのを期待していましたが、、、 1. beforeA 2. beforeB 3. afterA 4. afterB 5. result A,result B

実際には以下のように出力されました。

beforeA
afterA
beforeB
afterB
result A,result B

改善版

ソース

以下のように実装すると期待どおりに動作しました。

fun main() = runBlocking {
    val resultADeferred = async { methodA() }
    val resultBDeferred = async { methodB() }
    println("${resultADeferred.await()}, ${resultBDeferred.await()}")
}

private suspend fun methodA() = coroutineScope {
    println("beforeA")
    delay(1000)
    println("afterA")
    "result A"
}

private suspend fun methodB() = coroutineScope {
    println("beforeB")
    delay(3000)
    println("afterB")
    "result B"
}

出力結果

beforeA
beforeB
afterA
afterB
result A, result B

違うところ

async awaitを宣言するところをmainメソッドの中にすることで期待どおりに動くようになりました。

まとめ

どうしても並列処理が期待どおりに動かなくて調査していたところ、このブログに記載した 部分が問題となり並列処理が動いていないことがわかりました。 今回はなぜ宣言場所で並列処理が動かないかについては言語化していないので改めて してみたいと思います。

本記事で使ったソースはこちら github.com