気軽に楽しくプログラムと遊ぶ

自分が興味があってためになるかもって思う情報を提供しています。

Kotlin Coroutines 非同期処理

非同期処理で用いるコレクション Sequence

val numberSeq = (1..3).asSequence()
val resultSeq = numberSeq
    .map { println("1st map: $it"); it + 1 }
    .map { println("2nd map: $it"); it + 2 }
    .toList()
println(resultSeq)

Sequenceは、遅延リストのためtoList()が処理される段階で処理が出力される。 mapの処理がいくら呼ばれてもprintlnは実行されず、toListが呼ばれたときにはじめて実行される
以下のような出力を行う。

1st map: 1
2nd map: 2
1st map: 2
2nd map: 3
1st map: 3
2nd map: 4
[4, 5, 6]

一つ目のmapの一つ目の要素、2つ目のmapの一つ目の要素という ように処理が進んでいく。
Sequenceでなく、Listだと、一つ目のmapの全要素の出力後に2つ目のmapの要素が表示される

非同期に計算される複数の値を返却する Flowを使った実装例

flowOnで、Coroutinesコンテキストを割り当てて、新たなスレッドで処理を開始する。 bufferで、前処理結果をためつつ、並列して重めの処理を捌いていく。

findHistory(param) // flowを返却するメソッド
            .flowOn(Dispatchers.IO)
            .mapNotNull { history ->
                runCatching {
                    service.getSampleInfo(history.Id)
                }.fold(
                    onSuccess = {
                        history to it
                    },
                    onFailure = {
                        log.error("error")
                        null
                    },
                )
            }
            .filter { (history,  _) -> // 条件に合致しないものをフィルタする
                when {
                    history.isA -> {
                        false
                    }
                    history.isB -> {
                        false
                    }
                   else -> true
                }
            }
            .buffer() // 上記処理をバッファしつつ、下記処理と並列実行
            .map { (history, order, shop) ->
                       // 重めの処理
                    },
                )
            }
            .toList()

その他 非同期処理での留意点

  • withContext
    • コルーチン内のコンテキスト(Dispachers.IOに切り替える)
    • 時間のかかるブロッキング処理を内部で処理する。
    • コルーチンのsuspendメソッドなどノンブロッキング処理になっている場合は、この中に書く必要はない
  • スレッドローカルに保存するライブラリに注意

参考URL