プログラム 技術

Kotlinで非同期処理を実装する

今回はKotlinでの非同期処理についてになります。非同期処理は【kotlinx-coroutines-core】モジュールを使用しています

名称バージョン
jdk21
Kotlin2.1.20
kotlinx-coroutines-core1.10.2

Gradleを更新する

【kotlinx-coroutines-core】を使用するために『build.gradle.kts』ファイルに対して以下の内容を追加し、Gradleを更新します


dependencies {
    testImplementation(kotlin("test"))
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")  // 追加
}

非同期処理を待機する

まずは、非同期処理で一番大事な非同期処理が終了するまで待機するための方法についてです、それを実現するためには「runBlocking」を使用する形になります

import kotlinx.coroutines.*

// 関数内での使用例
fun main() {
    println("start")
    runBlocking {
        println("coroutine!")
    }
    println("end")
}

// 関数自体での使用例
fun main() = runBlocking {
    println("Start")

    println("End")
}

これで非同期処理を実施しても、非同期処理が完了していないのに本筋の処理が終了してしまうということは防ぐことができます

スレッドの待機

続いては処理をスレッドごとに実行した際に、それに対する挙動についてになります

すべてが終わるまで待機

この方法では実行したスレッドすべてが正常終了するまで待機する形となり、実行したスレッドいずれかでエラーが発生すると例外処理が発生します

suspend fun fetchA(): String {
    delay(1000) // 模擬的な非同期処理
    return "A"
}

suspend fun fetchB(): String {
    delay(2000) // こちらは時間がかかる
    return "B"
}

// CPUバウンド処理向けスレッドプールで実行
val deferredA = async(Dispatchers.Default) { fetchA() }
val deferredB = async(Dispatchers.Default) { fetchB() }

// awaitAll で両方を待つ(どちらかが失敗すると例外が伝播)
try {
    val (a, b) = awaitAll(deferredA, deferredB)
    println("Results: $a, $b")
} catch (e: Exception) {
    println("Error occurred: ${e.message}")
}

タイムアウト付きで待機

こちらではスレッドが指定した時間以内に処理が終了したかどうかの判定ができるようになっています

// タイムアウト付きで待つ。 タイムアウト時、例外が投げられる
// タイムアウト発生時、ブロック内の処理はキャンセル
try {
    withTimeout(1500) {
        val a = async { fetchA() }
        val b = async { fetchB() }
        listOf(a.await(), b.await()) 
    }
} catch (e: TimeoutCancellationException) {
    println("Timeout! (${e.message})")
}

// タイムアウト付きで待つ。 タイムアウト時、null になる可能性あり
// タイムアウト発生時、ブロック内の処理はキャンセル
val resultWithTimeout = withTimeoutOrNull(1500) {
    // fetchB は 2000ms かかるためタイムアウトされる
    val a = async { fetchA() }
    val b = async { fetchB() }
    listOf(a.await(), b.await())
}

println("Result with timeout: $resultWithTimeout") // null になる可能性あり

一方の失敗が他方をキャンセルしない待機

最初に紹介したものとは別に別スレッド上でエラーが発生しても、他のスレッドへは影響をあたえないものとなっています

// 一方の失敗が他方をキャンセルしない
supervisorScope {
    val sa = async {
        try {
            fetchA()
        } catch (e: Throwable) {
            "A failed"
        }
    }

    val sb = async {
        throw RuntimeException("failed B")
    }
    println("supervisor results: ${sa.await()}, ${runCatching { sb.await() }.exceptionOrNull()}")
}

今回紹介したものを使用することで処理時間の短縮や通信処理などを実行する際に便利だと思いますので参考になれば

会社紹介

私が所属しているアドバンスド・ソリューション株式会社(以下、ADS)は一緒に働く仲間を募集しています

会社概要
「技術」×「知恵」=顧客課題の解決・新しい価値の創造

この方程式の実現はADSが大切にしている考えで、技術を磨き続けるgeekさと、顧客を思うloveがあってこそ実現できる世界観だと思っています
この『love & geek』の精神さえあれば、得意不得意はno problem!
技術はピカイチだけど顧客折衝はちょっと苦手。OKです。技術はまだ未熟だけど顧客と知恵を出し合って要件定義するのは大好き。OKです
凸凹な社員の集まり、色んなカラーや柄の個性が集まっているからこそ、常に新しいソリューションが生まれています

ミッション
私たちは、テクノロジーを活用し、業務や事業の生産性向上と企業進化を支援します

ホームページ
アドバンスド・ソリューション株式会社|ADS Co., Ltd.
アドバンスド・ソリューション株式会社|ADS Co., Ltd.

Microsoft 365/SharePoint/Power Platform/Azure による DX コンサル・シス ...

サイトへ移動

PR

-プログラム, 技術
-